<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>SpringCloud学习笔记 | Jixer的小屋</title><meta name="author" content="Jixer"><meta name="copyright" content="Jixer"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="笔记参考博客：  https:&#x2F;&#x2F;blog.csdn.net&#x2F;u011863024&#x2F;article&#x2F;details&#x2F;114298270 https:&#x2F;&#x2F;blog.csdn.net&#x2F;u011863024&#x2F;article&#x2F;details&#x2F;114298282 https:&#x2F;&#x2F;blog.csdn.net&#x2F;u011863024&#x2F;article&#x2F;details&#x2F;114298288  环境搭建约定 &gt; 配">
<meta property="og:type" content="article">
<meta property="og:title" content="SpringCloud学习笔记">
<meta property="og:url" content="http://www.lijunxi.site/posts/1476420007/index.html">
<meta property="og:site_name" content="Jixer的小屋">
<meta property="og:description" content="笔记参考博客：  https:&#x2F;&#x2F;blog.csdn.net&#x2F;u011863024&#x2F;article&#x2F;details&#x2F;114298270 https:&#x2F;&#x2F;blog.csdn.net&#x2F;u011863024&#x2F;article&#x2F;details&#x2F;114298282 https:&#x2F;&#x2F;blog.csdn.net&#x2F;u011863024&#x2F;article&#x2F;details&#x2F;114298288  环境搭建约定 &gt; 配">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://q1.qlogo.cn/g?b=qq&nk=2770063826&s=640">
<meta property="article:published_time" content="2024-01-16T15:55:49.000Z">
<meta property="article:modified_time" content="2024-05-07T03:10:23.281Z">
<meta property="article:author" content="Jixer">
<meta property="article:tag" content="SpringCloud">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://q1.qlogo.cn/g?b=qq&nk=2770063826&s=640"><link rel="shortcut icon" href="/img/logo/favicon.ico"><link rel="canonical" href="http://www.lijunxi.site/posts/1476420007/index.html"><link rel="preconnect"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css?v=4.13.0"><link rel="stylesheet" href="/pluginsSrc/@fortawesome/fontawesome-free/css/all.min.css?v=6.5.1"><link rel="stylesheet" href="/pluginsSrc/@fancyapps/ui/dist/fancybox/fancybox.css?v=5.0.33" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = {
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":true,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"找不到您查询的内容：${query}","hits_stats":"共找到 ${hits} 篇文章"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlight.js","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  dateSuffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  infinitegrid: {
    js: '/pluginsSrc/@egjs/infinitegrid/dist/infinitegrid.min.js?v=4.11.1',
    buttonText: '加载更多'
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: false,
  },
  autoDarkmode: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'SpringCloud学习笔记',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2024-05-07 11:10:23'
}</script><script>(win=>{
      win.saveToLocal = {
        set: (key, value, ttl) => {
          if (ttl === 0) return
          const now = Date.now()
          const expiry = now + ttl * 86400000
          const item = {
            value,
            expiry
          }
          localStorage.setItem(key, JSON.stringify(item))
        },
      
        get: key => {
          const itemStr = localStorage.getItem(key)
      
          if (!itemStr) {
            return undefined
          }
          const item = JSON.parse(itemStr)
          const now = Date.now()
      
          if (now > item.expiry) {
            localStorage.removeItem(key)
            return undefined
          }
          return item.value
        }
      }
    
      win.getScript = (url, attr = {}) => new Promise((resolve, reject) => {
        const script = document.createElement('script')
        script.src = url
        script.async = true
        script.onerror = reject
        script.onload = script.onreadystatechange = function() {
          const loadState = this.readyState
          if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
          script.onload = script.onreadystatechange = null
          resolve()
        }

        Object.keys(attr).forEach(key => {
          script.setAttribute(key, attr[key])
        })

        document.head.appendChild(script)
      })
    
      win.getCSS = (url, id = false) => new Promise((resolve, reject) => {
        const link = document.createElement('link')
        link.rel = 'stylesheet'
        link.href = url
        if (id) link.id = id
        link.onerror = reject
        link.onload = link.onreadystatechange = function() {
          const loadState = this.readyState
          if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
          link.onload = link.onreadystatechange = null
          resolve()
        }
        document.head.appendChild(link)
      })
    
      win.activateDarkMode = () => {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = () => {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
        if (t === 'dark') activateDarkMode()
        else if (t === 'light') activateLightMode()
      
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
      const detectApple = () => {
        if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
          document.documentElement.classList.add('apple')
        }
      }
      detectApple()
    })(window)</script><link rel="stylesheet" href="/css/custom-all-min.css"><link rel="stylesheet" href="/css/custom-fancybox-min.css"><link rel="stylesheet" href="/css/custom-share-min.css"><meta name="generator" content="Hexo 6.3.0"></head><body><div id="loading-box"><div class="loading-left-bg"></div><div class="loading-right-bg"></div><div class="spinner-box"><div class="configure-border-1"><div class="configure-core"></div></div><div class="configure-border-2"><div class="configure-core"></div></div><div class="loading-word">加载中...</div></div></div><script>(()=>{
  const $loadingBox = document.getElementById('loading-box')
  const $body = document.body
  const preloader = {
    endLoading: () => {
      $body.style.overflow = ''
      $loadingBox.classList.add('loaded')
    },
    initLoading: () => {
      $body.style.overflow = 'hidden'
      $loadingBox.classList.remove('loaded')
    }
  }

  preloader.initLoading()
  window.addEventListener('load',() => { preloader.endLoading() })

  if (false) {
    document.addEventListener('pjax:send', () => { preloader.initLoading() })
    document.addEventListener('pjax:complete', () => { preloader.endLoading() })
  }
})()</script><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="" data-original="https://q1.qlogo.cn/g?b=qq&amp;nk=2770063826&amp;s=640" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">52</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">19</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">7</div></a></div><hr class="custom-hr"/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fa fa-graduation-cap"></i><span> 文章</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw fa fa-archive"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw fa fa-folder-open"></i><span> 归档</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/links/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header"><nav id="nav"><span id="blog-info"><a href="/" title="Jixer的小屋"><span class="site-name">Jixer的小屋</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fa fa-graduation-cap"></i><span> 文章</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw fa fa-archive"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw fa fa-folder-open"></i><span> 归档</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/links/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">SpringCloud学习笔记</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2024-01-16T15:55:49.000Z" title="发表于 2024-01-16 23:55:49">2024-01-16</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2024-05-07T03:10:23.281Z" title="更新于 2024-05-07 11:10:23">2024-05-07</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">33.2k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>130分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="SpringCloud学习笔记"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><p>笔记参考博客：</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://blog.csdn.net/u011863024/article/details/114298270">https://blog.csdn.net/u011863024/article/details/114298270</a></li>
<li><a target="_blank" rel="noopener" href="https://blog.csdn.net/u011863024/article/details/114298282">https://blog.csdn.net/u011863024/article/details/114298282</a></li>
<li><a target="_blank" rel="noopener" href="https://blog.csdn.net/u011863024/article/details/114298288">https://blog.csdn.net/u011863024/article/details/114298288</a></li>
</ul>
<h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><p>约定 &gt; 配置 &gt; 编码</p>
<p>创建微服务cloud整体聚合父工程Project，有8个关键步骤：</p>
<p>1、New Project - maven工程 - create from archetype: maven-archetype-site<br>2、聚合总父工程名字<br>3、Maven选版本<br>4、工程名字<br>5、字符编码 - Settings - File encoding<br>6、注解生效激活 - Settings - Annotation Processors<br>7、Java编译版本选8<br>8、File Type过滤 - Settings - File Type</p>
<h3 id="复习"><a href="#复习" class="headerlink" title="复习"></a>复习</h3><h4 id="DependencyManagement和Dependencies"><a href="#DependencyManagement和Dependencies" class="headerlink" title="DependencyManagement和Dependencies"></a>DependencyManagement和Dependencies</h4><p>Maven使用<code>dependencyManagement</code>元素来提供了一种管理依赖版本号的方式。</p>
<p>通常会在一个组织或者项目的最顶层的父POM 中看到<code>dependencyManagement</code>元素。</p>
<p>使用pom.xml中的<code>dependencyManagement</code>元素能让所有在子项目中引用个依赖而不用显式的列出版本量。</p>
<p>Maven会沿着父子层次向上走，直到找到一个拥有<code>dependencyManagement</code>元素的项目，然后它就会使用这个<code>dependencyManagement</code>元素中指定的版本号。</p>
<p>说白了就是父项目用了版本号，子项目就可以不需要写版本号，便于维护</p>
<p><strong>注意</strong></p>
<ul>
<li><code>dependencyManagement</code>里只是<strong>声明依赖，并不实现引入，因此子项目需要显示的声明需要用的依赖</strong>*。</li>
<li>如果不在子项目中声明依赖，是不会从父项目中继承下来的；只有在子项目中写了该依赖项,并且没有指定具体版本，才会从父项目中继承该项，并且version和scope都读取自父pom。</li>
<li>如果子项目中指定了版本号，那么会使用子项目中指定的jar版本。</li>
</ul>
<h4 id="Maven跳过单元测试"><a href="#Maven跳过单元测试" class="headerlink" title="Maven跳过单元测试"></a>Maven跳过单元测试</h4><p>IDEA右侧旁的Maven插件有<code>Toggle &#39; Skip Tests&#39; Mode</code>按钮，这样maven可以跳过单元测试</p>
<p>父工程创建完成执行<code>mvn : install</code>将父工程发布到仓库方便子工程 继承</p>
<h2 id="Dashboard窗口"><a href="#Dashboard窗口" class="headerlink" title="Dashboard窗口"></a>Dashboard窗口</h2><ol>
<li>打开工程路径下的.idea文件夹的workspace.xml</li>
<li>在<code>&lt;component name=&quot;RunDashboard&quot;&gt;</code>中修改或添加以下代码：重启即可</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">option</span> <span class="attr">name</span>=<span class="string">&quot;configurationTypes&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">set</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">&quot;SpringBootApplicationConfigurationType&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">set</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br></pre></td></tr></table></figure>



<h2 id="支付模块构建"><a href="#支付模块构建" class="headerlink" title="支付模块构建"></a>支付模块构建</h2><p>创建微服务模块套路：</p>
<ol>
<li>建Module</li>
<li>改POM</li>
<li>写YML</li>
<li>主启动</li>
<li>业务类</li>
</ol>
<p><a target="_blank" rel="noopener" href="https://imgse.com/i/pPSszzn"><img src="" data-original="https://s1.ax1x.com/2023/07/29/pPSszzn.png" alt="pPSszzn.png"></a></p>
<h2 id="消费模块构建"><a href="#消费模块构建" class="headerlink" title="消费模块构建"></a>消费模块构建</h2><p><a target="_blank" rel="noopener" href="https://imgse.com/i/pPSyCLV"><img src="" data-original="https://s1.ax1x.com/2023/07/29/pPSyCLV.png" alt="pPSyCLV.png"></a></p>
<h2 id="Restemplate"><a href="#Restemplate" class="headerlink" title="Restemplate"></a>Restemplate</h2><p>RestTemplate提供了多种便捷访问远程Http服务的方法，是一种简单便捷的访问restful服务模板类，是Spring提供的用于访问Rest服务的客户端模板工具集</p>
<p>使用：</p>
<ul>
<li>使用restTemplate访问restful接口非常的简单粗暴无脑。</li>
<li><code>(url, requestMap, ResponseBean.class)</code>这三个参数分别代表。</li>
<li>REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 消费模块调用支付模块接口</span></span><br><span class="line">restTemplate.postForObject(<span class="string">&quot;http://localhost:8001/payment/create&quot;</span>, payment, CommonResult.class);</span><br></pre></td></tr></table></figure>

<ul>
<li><p>getForObject() &#x2F; getForEntity() - GET请求方法</p>
</li>
<li><p>getForObject()：返回对象为响应体中数据转化成的对象，基本上可以理解为Json。</p>
</li>
<li><p>getForEntity()：返回对象为ResponseEntity对象，包含了响应中的一些重要信息，比如响应头、响应状态码、响应体等。</p>
</li>
</ul>
<h2 id="工程重构"><a href="#工程重构" class="headerlink" title="工程重构"></a>工程重构</h2><p>观察cloud-consumer-order80与cloud-provider-payment8001两工程有重复代码（entities包下的实体）</p>
<p>1、新建cloud-api-commons来存放公共代码和一些配置类等等</p>
<p>2、添加pom文件</p>
<p>3、将cloud-consumer-order80与cloud-provider-payment8001两工程的公有entities包移至cloud-api-commons工程下</p>
<p>4、maven clean、install </p>
<p>5、将cloud-consumer-order80与cloud-provider-payment8001两工程的公有entities包移除</p>
<p>6、两个工程引入cloud-api-commons依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.ljx.springcloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>cloud-api-commons<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;project.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="知识点"><a href="#知识点" class="headerlink" title="知识点"></a>知识点</h2><p><a target="_blank" rel="noopener" href="https://imgse.com/i/pPSgBTK"><img src="" data-original="https://s1.ax1x.com/2023/07/29/pPSgBTK.png" alt="pPSgBTK.png"></a></p>
<p>最终需要在上述项目基础上一点点添加这些组件</p>
<h2 id="服务注册中心"><a href="#服务注册中心" class="headerlink" title="服务注册中心"></a>服务注册中心</h2><h3 id="Eureka"><a href="#Eureka" class="headerlink" title="Eureka"></a>Eureka</h3><h4 id="基础知识"><a href="#基础知识" class="headerlink" title="基础知识"></a>基础知识</h4><p>Eureka采用了CS的设计架构，Eureka Sever作为服务注册功能的服务器，它是服务注册中心。而系统中的其他微服务，使用Eureka的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/3956561052b9dc3909f16f1ff26d01bb.png" alt="aaa.png"></p>
<p><strong>Eureka包含两个组件:Eureka Server和Eureka Client</strong></p>
<p><strong>Eureka Server提供服务注册服务</strong></p>
<p>各个微服务节点通过配置启动后，会在EurekaServer中进行注册，这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息，服务节点的信息可以在界面中直观看到。</p>
<p><strong>EurekaClient通过注册中心进行访问</strong></p>
<p>它是一个Java客户端，用于简化Eureka Server的交互，客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后，将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳，EurekaServer将会从服务注册表中把这个服务节点移除（默认90秒)</p>
<h4 id="EurekaServer服务端安装"><a href="#EurekaServer服务端安装" class="headerlink" title="EurekaServer服务端安装"></a>EurekaServer服务端安装</h4><p>eurekaServer端服务注册中心，类似物业公司</p>
<p>1.创建名为cloud-eureka-server7001的Maven工程</p>
<p>2.修改pom.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-server<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.添加application.yml</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">7001</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">locathost</span> <span class="comment">#eureka服务端的实例名称</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="comment">#false表示不向注册中心注册自己。</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line">    <span class="comment">#false表示自己端就是注册中心，我的职责就是维护服务实例，并不需要去检索服务</span></span><br><span class="line">    <span class="attr">fetch-registry:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="comment">#设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址。</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://$&#123;eureka.instance.hostname&#125;:$&#123;server.port&#125;/eureka/</span></span><br></pre></td></tr></table></figure>

<p>4.主启动</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableEurekaServer</span></span><br></pre></td></tr></table></figure>

<p>5.测试运行<code>EurekaMain7001</code>，浏览器输入<code>http://localhost:7001/</code>回车，会查看到Spring Eureka服务主页。</p>
<h4 id="支付微服务8001入驻进EurekaServer"><a href="#支付微服务8001入驻进EurekaServer" class="headerlink" title="支付微服务8001入驻进EurekaServer"></a>支付微服务8001入驻进EurekaServer</h4><p>EurekaClient端cloud-provider-payment8001将注册进EurekaServer成为服务提供者provider，类似学校对外提供授课服务。</p>
<p>1.创建名为cloud-eureka-server7001的Maven工程</p>
<p>2.修改pom.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-server<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.添加application.yml</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">7001</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">locathost</span> <span class="comment">#eureka服务端的实例名称</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="comment">#false表示不向注册中心注册自己。</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line">    <span class="comment">#false表示自己端就是注册中心，我的职责就是维护服务实例，并不需要去检索服务</span></span><br><span class="line">    <span class="attr">fetch-registry:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="comment">#设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址。</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://$&#123;eureka.instance.hostname&#125;:$&#123;server.port&#125;/eureka/</span></span><br></pre></td></tr></table></figure>

<p>4.主启动</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableEurekaClient</span></span><br></pre></td></tr></table></figure>

<p>5.测试</p>
<ul>
<li><p>启动cloud-provider-payment8001和cloud-eureka-server7001工程（先启动）。</p>
</li>
<li><p>浏览器输入 - <a target="_blank" rel="noopener" href="http://localhost:7001/">http://localhost:7001/</a> 主页内的Instances currently registered with Eureka会显示cloud-provider-payment8001的配置文件application.yml设置的应用名<code>cloud-payment-service</code></p>
</li>
</ul>
<p>6.自我保护机制</p>
<p>EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARELESSER THAN THRESHOLD AND HENCFT ARE NOT BEING EXPIRED JUST TO BE SAFE.</p>
<p>紧急情况！EUREKA可能错误地声称实例在没有启动的情况下启动了。续订小于阈值，因此实例不会为了安全而过期。</p>
<h4 id="订单微服务80入驻进EurekaServer"><a href="#订单微服务80入驻进EurekaServer" class="headerlink" title="订单微服务80入驻进EurekaServer"></a>订单微服务80入驻进EurekaServer</h4><p>EurekaClient端cloud-consumer-order80将注册进EurekaServer成为服务消费者consumer，类似来上课消费的同学</p>
<p>1.cloud-consumer-order80</p>
<p>2.POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloud-order-service</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="comment">#表示是否将自己注册进Eurekaserver默认为true。</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line">    <span class="comment">#是否从EurekaServer抓取已有的注册信息，默认为true。单节点无所谓，集群必须设置为true才能配合ribbon使用负载均衡</span></span><br><span class="line">    <span class="attr">fetchRegistry:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka</span></span><br></pre></td></tr></table></figure>

<p>4.主启动</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableEurekaClient</span></span><br></pre></td></tr></table></figure>

<p>5.测试</p>
<ul>
<li>启动cloud-provider-payment8001、cloud-eureka-server7001（先启动）和cloud-consumer-order80这三工程。</li>
<li>浏览器输入 <a target="_blank" rel="noopener" href="http://localhost:7001/">http://localhost:7001</a> , 在主页的Instances currently registered with Eureka将会看到cloud-provider-payment8001、cloud-consumer-order80两个工程名。</li>
</ul>
<h4 id="Eureka集群原理说明"><a href="#Eureka集群原理说明" class="headerlink" title="Eureka集群原理说明"></a>Eureka集群原理说明</h4><p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/14570c4b7c4dd8653be6211da2675e45.png" alt="img.png"></p>
<p>问题：微服务RPC远程服务调用最核心的是什么？<br>高可用，试想你的注册中心只有一个only one，万一它出故障了，会导致整个为服务环境不可用。</p>
<p>解决办法：搭建Eureka注册中心集群，实现负载均衡+故障容错。</p>
<p><strong>互相注册，相互守望</strong>。</p>
<h4 id="Eureka集群环境构建"><a href="#Eureka集群环境构建" class="headerlink" title="Eureka集群环境构建"></a>Eureka集群环境构建</h4><p>创建cloud-eureka-server7002工程</p>
<ul>
<li>找到C:\Windows\System32\drivers\etc路径下的hosts文件，修改映射配置添加进hosts文件</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1 eureka7001.com</span><br><span class="line">127.0.0.1 eureka7002.com</span><br></pre></td></tr></table></figure>

<ul>
<li>修改cloud-eureka-server7001配置文件</li>
</ul>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">7001</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">eureka7001.com</span> <span class="comment">#eureka服务端的实例名称</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">false</span>     <span class="comment">#false表示不向注册中心注册自己。</span></span><br><span class="line">    <span class="attr">fetch-registry:</span> <span class="literal">false</span>     <span class="comment">#false表示自己端就是注册中心，我的职责就是维护服务实例，并不需要去检索服务</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">    <span class="comment">#集群指向其它eureka</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://eureka7002.com:7002/eureka/</span></span><br><span class="line">    <span class="comment">#单机就是7001自己</span></span><br><span class="line">      <span class="comment">#defaultZone: http://eureka7001.com:7001/eureka/</span></span><br></pre></td></tr></table></figure>

<ul>
<li>修改cloud-eureka-server7002配置文件</li>
</ul>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">7002</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">eureka7002.com</span> <span class="comment">#eureka服务端的实例名称</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">false</span>     <span class="comment">#false表示不向注册中心注册自己。</span></span><br><span class="line">    <span class="attr">fetch-registry:</span> <span class="literal">false</span>     <span class="comment">#false表示自己端就是注册中心，我的职责就是维护服务实例，并不需要去检索服务</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">    <span class="comment">#集群指向其它eureka</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka/</span></span><br><span class="line">    <span class="comment">#单机就是7002自己</span></span><br><span class="line">      <span class="comment">#defaultZone: http://eureka7002.com:7002/eureka/</span></span><br></pre></td></tr></table></figure>

<h4 id="订单支付两微服务注册进Eureka集群"><a href="#订单支付两微服务注册进Eureka集群" class="headerlink" title="订单支付两微服务注册进Eureka集群"></a>订单支付两微服务注册进Eureka集群</h4><p>将它们的配置文件的eureka.client.service-url.defaultZone进行修改</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="comment">#表示是否将自己注册进Eurekaserver默认为true。</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line">    <span class="comment">#是否从EurekaServer抓取已有的注册信息，默认为true。单节点无所谓，集群必须设置为true才能配合ribbon使用负载均衡</span></span><br><span class="line">    <span class="attr">fetchRegistry:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="comment">#注册到集群中</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka,</span> <span class="string">http://eureka7002.com:7002/eureka</span></span><br></pre></td></tr></table></figure>

<ol>
<li>先要启动EurekaServer，7001&#x2F;7002服务</li>
<li>再要启动服务提供者provider，8001</li>
<li>再要启动消费者，80</li>
<li>浏览器输入 - <a target="_blank" rel="noopener" href="http://localhost/consumer/payment/get/1">http://localhost/consumer/payment/get/1</a></li>
</ol>
<h4 id="支付微服务集群配置"><a href="#支付微服务集群配置" class="headerlink" title="支付微服务集群配置"></a>支付微服务集群配置</h4><p>新建cloud-provider-payment8002参考cloud-provicer-payment8001</p>
<p><strong>负载均衡</strong></p>
<p>cloud-consumer-order80订单服务访问地址不能写死</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">PAYMENT_URL</span> <span class="operator">=</span> <span class="string">&quot;http://CLOUD-PAYMENT-SERVICE&quot;</span>;</span><br></pre></td></tr></table></figure>

<p>使用<code>@LoadBalanced</code>注解赋予RestTemplate负载均衡的能力</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ApplicationContextConfig</span> &#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@LoadBalanced</span><span class="comment">//使用@LoadBalanced注解赋予RestTemplate负载均衡的能力</span></span><br><span class="line">    <span class="keyword">public</span> RestTemplate <span class="title function_">getRestTemplate</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="actuator微服务信息完善"><a href="#actuator微服务信息完善" class="headerlink" title="actuator微服务信息完善"></a>actuator微服务信息完善</h4><p>主机名称：服务名称修改（也就是将IP地址，换成可读性高的名字）</p>
<p>修改cloud-provider-payment8001，cloud-provider-payment8002</p>
<p>修改部分 - YML - eureka.instance.instance-id</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="string">...</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">instance-id:</span> <span class="string">payment8001</span> <span class="comment">#显示名称</span></span><br><span class="line">    <span class="attr">prefer-ip-address:</span> <span class="literal">true</span> <span class="comment">#显示ip地址</span></span><br></pre></td></tr></table></figure>

<p>修改之后</p>
<p>eureka主页将显示payment8001，payment8002代替原来显示的IP地址。</p>
<h4 id="服务发现Discovery"><a href="#服务发现Discovery" class="headerlink" title="服务发现Discovery"></a>服务发现Discovery</h4><p>对于注册进eureka里面的微服务，可以通过服务发现来获得该服务的信息</p>
<h4 id="Eureka自我保护理论知识"><a href="#Eureka自我保护理论知识" class="headerlink" title="Eureka自我保护理论知识"></a>Eureka自我保护理论知识</h4><p>保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式，Eureka Server将会尝试保护其服务注册表中的信息，不再删除服务注册表中的数据，也就是不会注销任何微服务。</p>
<p>如果在Eureka Server的首页看到以下这段提示，则说明Eureka进入了保护模式:</p>
<blockquote>
<p>EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THANTHRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUSTTO BE SAFE</p>
</blockquote>
<p><strong>导致原因</strong></p>
<p>一句话：某时刻某一个微服务不可用了，Eureka不会立刻清理，依旧会对该微服务的信息进行保存。</p>
<p>属于CAP里面的AP分支。</p>
<p><strong>为什么会产生Eureka自我保护机制?</strong></p>
<p>为了EurekaClient可以正常运行，防止与EurekaServer网络不通情况下，EurekaServer不会立刻将EurekaClient服务剔除</p>
<p><strong>什么是自我保护模式?</strong></p>
<p>认情况下，如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳，EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时，微服务与EurekaServer之间无法正常通信，以上行为可能变得非常危险了——因为微服务本身其实是健康的，此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障)，那么这个节点就会进入自我保护模式。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/264b66e8099a3761beaea2ba44b8fc5e.png" alt="b.png"></p>
<p><strong>在自我保护模式中，Eureka Server会保护服务注册表中的信息，不再注销任何服务实例</strong></p>
<p>它的设计哲学就是宁可保留错误的服务注册信息，也不盲目注销任何可能健康的服务实例。一句话讲解：<strong>好死不如赖活着</strong>。</p>
<p>综上，自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务（健康的微服务和不健康的微服务都会保留）也不盲目注销任何健康的微服务。使用自我保护模式，可以让Eureka集群更加的健壮、稳定。</p>
<p><strong>禁止自我保护</strong></p>
<p>出厂默认，自我保护机制是开启的</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="string">...</span></span><br><span class="line">  <span class="attr">server:</span></span><br><span class="line">    <span class="comment">#关闭自我保护机制，保证不可用服务被及时踢除</span></span><br><span class="line">    <span class="attr">enable-self-preservation:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">eviction-interval-timer-in-ms:</span> <span class="number">2000</span></span><br></pre></td></tr></table></figure>

<p>关闭效果：spring-eureka主页会显示出一句：</p>
<p><strong>THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK&#x2F;OTHER PROBLEMS.</strong></p>
<h3 id="Zookeeper"><a href="#Zookeeper" class="headerlink" title="Zookeeper"></a>Zookeeper</h3><p>Linux下载</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz</span><br></pre></td></tr></table></figure>

<p>解压</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz</span><br></pre></td></tr></table></figure>

<p>启动</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./zkServer.sh start</span><br></pre></td></tr></table></figure>

<p>关闭防火墙</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl stop ufw.service</span><br></pre></td></tr></table></figure>

<h4 id="支付服务注册进zookeeper"><a href="#支付服务注册进zookeeper" class="headerlink" title="支付服务注册进zookeeper"></a>支付服务注册进zookeeper</h4><p>1.新建名为cloud-provider-payment8004的Maven工程。</p>
<p>2.POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- SpringBoot整合zookeeper客户端 --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-zookeeper-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">      <span class="comment">&lt;!--先排除自带的zookeeper3.5.3 防止与3.4.9起冲突--&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.zookeeper<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>zookeeper<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!--添加zookeeper3.4.9版本--&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.zookeeper<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>zookeeper<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.4.9<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#8004表示注册到zookeeper服务器的支付服务提供者端口号</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8004</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#服务别名----注册zookeeper到注册中心名称</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloud-provider-payment</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">zookeeper:</span></span><br><span class="line">      <span class="attr">connect-string:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:2181</span> <span class="comment"># 192.168.111.144:2181 #</span></span><br></pre></td></tr></table></figure>

<p>4.主启动类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableDiscoveryClient</span><span class="comment">//该注解用于向使用consul或者zookeeper作为注册中心时注册服务</span></span><br></pre></td></tr></table></figure>

<p>5.Controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;server.port&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String serverPort;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(value = &quot;/payment/zk&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentzk</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;springcloud with zookeeper: &quot;</span>+serverPort+<span class="string">&quot;\t&quot;</span>+ UUID.randomUUID().toString();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="订单服务注册进zookeeper"><a href="#订单服务注册进zookeeper" class="headerlink" title="订单服务注册进zookeeper"></a>订单服务注册进zookeeper</h4><p>1.新建cloud-consumerzk-order80（与上面类似）</p>
<p>2.POM</p>
<p>3.YML</p>
<p>4.主启动</p>
<p>5.配置类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ApplicationContextConfig</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@LoadBalanced</span></span><br><span class="line">    <span class="keyword">public</span> RestTemplate <span class="title function_">getRestTemplate</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>6.业务类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderZKController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">INVOKE_URL</span> <span class="operator">=</span> <span class="string">&quot;http://cloud-provider-payment&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(value = &quot;/consumer/payment/zk&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> restTemplate.getForObject(INVOKE_URL+<span class="string">&quot;/payment/zk&quot;</span>,String.class);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>7.访问测试地址 - <a target="_blank" rel="noopener" href="http://localhost/consumer/payment/zk">http://localhost/consumer/payment/zk</a></p>
<h3 id="Consul"><a href="#Consul" class="headerlink" title="Consul"></a>Consul</h3><p>官网链接：<a target="_blank" rel="noopener" href="https://www.consul.io/">https://www.consul.io/</a></p>
<p>Consul是一套开源的分布式服务发现和配置管理系统，由HashiCorp 公司用Go语言开发。</p>
<p>提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用，也可以一起使用以构建全方位的服务网格，总之Consul提供了一种完整的服务网格解决方案。</p>
<p>它具有很多优点。包括：基于raft协议，比较简洁；支持健康检查，同时支持HTTP和DNS协议支持跨数据中心的WAN集群提供图形界面跨平台，支持Linux、Mac、Windows。</p>
<p><strong>能干嘛？</strong></p>
<ul>
<li>服务发现 - 提供HTTP和DNS两种发现方式。</li>
<li>健康监测 - 支持多种方式，HTTP、TCP、Docker、Shell脚本定制化</li>
<li>KV存储 - Key、Value的存储方式</li>
<li>多数据中心 - Consul支持多数据中心</li>
<li>可视化Web界面</li>
</ul>
<p><strong>相关命令</strong></p>
<ul>
<li>查看版本：<code>consul -v</code></li>
<li>开发模式启动<code>consul agent -dev</code></li>
</ul>
<p>浏览器输入 - <a target="_blank" rel="noopener" href="http://localhost:8500/">http://localhost:8500/</a> - 打开Consul控制页。</p>
<h4 id="服务提供者注册进Consul"><a href="#服务提供者注册进Consul" class="headerlink" title="服务提供者注册进Consul"></a>服务提供者注册进Consul</h4><p>1.新建Module支付服务provider8006</p>
<p>2.POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-consul-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.YML</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">###consul服务端口号</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8006</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">consul-provider-payment</span></span><br><span class="line"><span class="comment">####consul注册中心地址</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">consul:</span></span><br><span class="line">      <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">      <span class="attr">port:</span> <span class="number">8500</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="comment">#hostname: 127.0.0.1</span></span><br><span class="line">        <span class="attr">service-name:</span> <span class="string">$&#123;spring.application.name&#125;</span></span><br></pre></td></tr></table></figure>

<p>4.主启动类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableDiscoveryClient</span></span><br></pre></td></tr></table></figure>

<p>5.业务类Controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;server.port&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String serverPort;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(value = &quot;/payment/consul&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentConsul</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;springcloud with consul: &quot;</span>+serverPort+<span class="string">&quot;\t   &quot;</span>+ UUID.randomUUID().toString();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>6.验证测试</p>
<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:8006/payment/consul">http://localhost:8006/payment/consul</a></li>
<li><a target="_blank" rel="noopener" href="http://localhost:8500/">http://localhost:8500</a> - 会显示provider8006</li>
</ul>
<h4 id="服务消费者注册进Consul"><a href="#服务消费者注册进Consul" class="headerlink" title="服务消费者注册进Consul"></a>服务消费者注册进Consul</h4><p>1.新建Module消费服务order80 - cloud-consumerconsul-order80</p>
<p>2.POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-consul-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.YML</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">###consul服务端口号</span><br><span class="line">server:</span><br><span class="line">  port: <span class="number">80</span></span><br><span class="line"></span><br><span class="line">spring:</span><br><span class="line">  application:</span><br><span class="line">    name: cloud-consumer-order</span><br><span class="line">####consul注册中心地址</span><br><span class="line">  cloud:</span><br><span class="line">    consul:</span><br><span class="line">      host: localhost</span><br><span class="line">      port: <span class="number">8500</span></span><br><span class="line">      discovery:</span><br><span class="line">        #hostname: <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span></span><br><span class="line">        service-name: $&#123;spring.application.name&#125;</span><br></pre></td></tr></table></figure>

<p>4.主启动类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableDiscoveryClient</span> <span class="comment">//该注解用于向使用consul或者zookeeper作为注册中心时注册服务</span></span><br></pre></td></tr></table></figure>

<p>5.配置Bean</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ApplicationContextConfig</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@LoadBalanced</span></span><br><span class="line">    <span class="keyword">public</span> RestTemplate <span class="title function_">getRestTemplate</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>6.业务类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderConsulController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">INVOKE_URL</span> <span class="operator">=</span> <span class="string">&quot;http://consul-provider-payment&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(value = &quot;/consumer/payment/consul&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> restTemplate.getForObject(INVOKE_URL+<span class="string">&quot;/payment/consul&quot;</span>,String.class);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>7.验证测试</p>
<p>运行consul，cloud-providerconsul-payment8006，cloud-consumerconsul-order80</p>
<p><a target="_blank" rel="noopener" href="http://localhost:8500/">http://localhost:8500/</a> 主页会显示出consul，cloud-providerconsul-payment8006，cloud-consumerconsul-order80三服务。</p>
<p>8.访问测试地址 - <a target="_blank" rel="noopener" href="http://localhost/consumer/payment/consul">http://localhost/consumer/payment/consul</a></p>
<h3 id="三个注册中心异同点"><a href="#三个注册中心异同点" class="headerlink" title="三个注册中心异同点"></a>三个注册中心异同点</h3><table>
<thead>
<tr>
<th>组件名</th>
<th>语言CAP</th>
<th>服务健康检查</th>
<th>对外暴露接口</th>
<th>Spring Cloud集成</th>
</tr>
</thead>
<tbody><tr>
<td>Eureka</td>
<td>Java</td>
<td>AP</td>
<td>可配支持</td>
<td>HTTP</td>
</tr>
<tr>
<td>Consul</td>
<td>Go</td>
<td>CP</td>
<td>支持</td>
<td>HTTP&#x2F;DNS</td>
</tr>
<tr>
<td>Zookeeper</td>
<td>Java</td>
<td>CP</td>
<td>支持客户端</td>
<td>已集成</td>
</tr>
</tbody></table>
<p>CAP：</p>
<ul>
<li>C：Consistency (强一致性)</li>
<li>A：Availability (可用性)</li>
<li>P：Partition tolerance （分区容错性)</li>
</ul>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/b41e0791c9652955dd3a2bc9d2d60983.png" alt="111.png"></p>
<p><strong>最多只能同时较好的满足两个。</strong></p>
<p>CAP理论的核心是：<strong>一个分布式系统不可能同时很好的满足一致性，可用性和分区容错性这三个需求</strong>。</p>
<p>因此，根据CAP原理将NoSQL数据库分成了满足CA原则、满足CP原则和满足AP原则三大类:</p>
<p>CA - 单点集群，满足—致性，可用性的系统，通常在可扩展性上不太强大。<br>CP - 满足一致性，分区容忍必的系统，通常性能不是特别高。<br>AP - 满足可用性，分区容忍性的系统，通常可能对一致性要求低一些。</p>
<h4 id="AP架构（Eureka）"><a href="#AP架构（Eureka）" class="headerlink" title="AP架构（Eureka）"></a>AP架构（Eureka）</h4><p>当网络分区出现后，为了保证可用性，系统B可以返回旧值，保证系统的可用性。</p>
<p>结论：违背了一致性C的要求，只满足可用性和分区容错，即AP</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/2d07748539300b9c466eb1d9bac5cd1b.png" alt="123.png"></p>
<h4 id="CP架构（ZooKeeper-Consul）"><a href="#CP架构（ZooKeeper-Consul）" class="headerlink" title="CP架构（ZooKeeper&#x2F;Consul）"></a>CP架构（ZooKeeper&#x2F;Consul）</h4><p>当网络分区出现后，为了保证一致性，就必须拒接请求，否则无法保证一致性。</p>
<p>结论：违背了可用性A的要求，只满足一致性和分区容错，即CP。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/c6f2926a97420015fcebc89b094c5598.png" alt="e21x.png"></p>
<p>CP 与 AP 对立同一的矛盾关系。</p>
<h2 id="服务调用"><a href="#服务调用" class="headerlink" title="服务调用"></a>服务调用</h2><h3 id="Ribbon"><a href="#Ribbon" class="headerlink" title="Ribbon"></a>Ribbon</h3><p>Spring Cloud Ribbon是基于Netflix Ribbon实现的一套<strong>客户端负载均衡的工具</strong>。</p>
<p>简单的说，Ribbon是Netflix发布的开源项目，主要功能是提供<strong>客户端的软件负载均衡算法和服务调用</strong>。Ribbon客户端组件提供一系列完善的配置项如连接超时，重试等。</p>
<p>Ribbon未来可能被Spring Cloud LoadBalacer替代。</p>
<p><strong>LB负载均衡(Load Balance)是什么</strong></p>
<p>简单的说就是将用户的请求平摊的分配到多个服务上，从而达到系统的HA (高可用)。</p>
<p>常见的负载均衡有软件Nginx，LVS，硬件F5等。</p>
<p><strong>Ribbon本地负载均衡客户端 VS Nginx服务端负载均衡区别</strong></p>
<p>Nginx是服务器负载均衡，客户端所有请求都会交给nginx，然后由nginx实现转发请求。即负载均衡是由服务端实现的。<br>Ribbon本地负载均衡，在调用微服务接口时候，会在注册中心上获取注册信息服务列表之后缓存到JVM本地，从而在本地实现RPC远程服务调用技术。</p>
<p><strong>集中式LB</strong></p>
<p>即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件，如F5, 也可以是软件，如nginx)，由该设施负责把访问请求通过某种策略转发至服务的提供方;</p>
<p><strong>进程内LB</strong></p>
<p>将LB逻辑集成到消费方，消费方从服务注册中心获知有哪些地址可用，然后自己再从这些地址中选择出一个合适的服务器。</p>
<p>Ribbon就属于进程内LB，它只是一个类库，集成于消费方进程，消费方通过它来获取到服务提供方的地址。</p>
<p>一句话</p>
<p><strong>负载均衡 + RestTemplate调用</strong></p>
<h4 id="Ribbon的负载均衡和Rest调用"><a href="#Ribbon的负载均衡和Rest调用" class="headerlink" title="Ribbon的负载均衡和Rest调用"></a>Ribbon的负载均衡和Rest调用</h4><p>总结：Ribbon其实就是一个软负载均衡的客户端组件，它可以和其他所需请求的客户端结合使用，和Eureka结合只是其中的一个实例。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/145b915e56a85383b3ad40f0bb2256e0.png" alt="1dc.png"></p>
<p>Ribbon在工作时分成两步：</p>
<ul>
<li>第一步先选择EurekaServer ,它优先选择在同一个区域内负载较少的server。</li>
<li>第二步再根据用户指定的策略，在从server取到的服务注册列表中选择一个地址。</li>
</ul>
<p>其中Ribbon提供了多种策略：比如轮询、随机和根据响应时间加权。</p>
<p><strong><code>spring-cloud-starter-netflix-eureka-client</code>自带了<code>spring-cloud-starter-ribbon</code>引用</strong></p>
<h4 id="Ribbon默认自带的负载规则"><a href="#Ribbon默认自带的负载规则" class="headerlink" title="Ribbon默认自带的负载规则"></a>Ribbon默认自带的负载规则</h4><p>lRule：根据特定算法中从服务列表中选取一个要访问的服务</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/87243c00c0aaea211819c0d8fc97e445.png" alt="asdacg2.png"></p>
<ul>
<li>RoundRobinRule 轮询</li>
<li>RandomRule 随机</li>
<li>RetryRule 先按照RoundRobinRule的策略获取服务，如果获取服务失败则在指定时间内会进行重</li>
<li>WeightedResponseTimeRule 对RoundRobinRule的扩展，响应速度越快的实例选择权重越大，越容易被选择</li>
<li>BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务，然后选择一个并发量最小的服务</li>
<li>AvailabilityFilteringRule 先过滤掉故障实例，再选择并发较小的实例</li>
<li>ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器</li>
</ul>
<p><strong>Ribbon负载规则替换</strong></p>
<p>1.修改cloud-consumer-order80</p>
<p>2.注意配置细节</p>
<p>官方文档明确给出了警告：<strong>这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下，否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享，达不到特殊化定制的目的了（也就是说不要将Ribbon配置类与主启动类同包</strong>）</p>
<p>3.新建package - com.lun.myrule</p>
<p>4.在com.ljx.myrule下新建MySelfRule规则类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MySelfRule</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> IRule <span class="title function_">myRule</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RandomRule</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>5.主启动类添加</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RibbonClient(name = &quot;CLOUD-PAYMENT-SERVICE&quot;, configuration = MySelfRule.class)</span></span><br></pre></td></tr></table></figure>

<h3 id="OpenFeign"><a href="#OpenFeign" class="headerlink" title="OpenFeign"></a>OpenFeign</h3><p>Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。它的使用方法是定义一个服务接口然后在上面添加注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装，使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。</p>
<p>前面在使用Ribbon+RestTemplate时，利用RestTemplate对http请求的封装处理，形成了一套模版化的调用方法。但是在实际开发中，由于对服务依赖的调用可能不止一处，往往一个接口会被多处调用，所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以，Feign在此基础上做了进一步封装，由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下，我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可)，即可完成对服务提供方的接口绑定，简化了使用Spring cloud Ribbon时，自动封装服务调用客户端的开发量。</p>
<p><strong>Feign集成了Ribbon</strong></p>
<p>利用Ribbon维护了Payment的服务列表信息，并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是，<strong>通过feign只需要定义服务绑定接口且以声明式的方法</strong>，优雅而简单的实现了服务调用。</p>
<h4 id="Feign和OpenFeign两者区别"><a href="#Feign和OpenFeign两者区别" class="headerlink" title="Feign和OpenFeign两者区别"></a>Feign和OpenFeign两者区别</h4><p><strong>Feign</strong>是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端Feign内置了Ribbon，用来做客户端负载均衡，去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口，调用这个接口，就可以调用服务注册中心的服务。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-feign<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>penFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解，如@RequesMapping等等。OpenFeign的@Feignclient可以解析SpringMVc的@RequestMapping注解下的接口，并通过动态代理的方式产生实现类，实现类中做负载均衡并调用其他服务。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-openfeign<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="OpenFeign服务调用"><a href="#OpenFeign服务调用" class="headerlink" title="OpenFeign服务调用"></a>OpenFeign服务调用</h4><p>接口+注解：微服务调用接口 + @FeignClient</p>
<p>1.新建cloud-consumer-feign-order80</p>
<p>2.POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-openfeign<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/</span></span><br></pre></td></tr></table></figure>

<p>4.主启动</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderFeignMain80</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        SpringApplication.run(OrderFeignMain80.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>5.业务类</p>
<p>业务逻辑接口+@FeignClient配置调用provider服务</p>
<p>新建PaymentFeignService接口并新增注解@FeignClient</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@FeignClient(value = &quot;CLOUD-PAYMENT-SERVICE&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">PaymentFeignService</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@GetMapping(value = &quot;/payment/get/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">getPaymentById</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Long id)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>注意：</strong>若有公共前缀api的请求，需要修改为<code>@FeignClient(value = &quot;xx&quot;, path=&quot;/api&quot;)</code></p>
<p>Controller类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderFeignController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> PaymentFeignService paymentFeignService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(value = &quot;/consumer/payment/get/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">getPaymentById</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Long id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> paymentFeignService.getPaymentById(id);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>6.测试</p>
<p>先启动2个eureka集群7001&#x2F;7002，再启动2个微服务8001&#x2F;8002，最后启动OpenFeign启动</p>
<p>访问<a target="_blank" rel="noopener" href="http://localhost/consumer/payment/get/1">http://localhost/consumer/payment/get/1</a></p>
<p><strong>Feign自带负载均衡配置项</strong></p>
<h4 id="OpenFeign超时控制"><a href="#OpenFeign超时控制" class="headerlink" title="OpenFeign超时控制"></a>OpenFeign超时控制</h4><p><strong>超时设置，故意设置超时演示出错情况</strong></p>
<p>1.服务提供方8001&#x2F;8002故意写暂停程序</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(value = &quot;/payment/feign/timeout&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">paymentFeignTimeout</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// 业务逻辑处理正确，但是需要耗费3秒钟</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> serverPort;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>2.服务消费方80添加超时方法PaymentFeignService</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(value = &quot;/payment/feign/timeout&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">paymentFeignTimeout</span><span class="params">()</span>;</span><br></pre></td></tr></table></figure>

<p>3.服务消费方80添加超时方法OrderFeignController</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(value = &quot;/consumer/payment/feign/timeout&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">paymentFeignTimeout</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">// OpenFeign客户端一般默认等待1秒钟</span></span><br><span class="line">    <span class="keyword">return</span> paymentFeignService.paymentFeignTimeout();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>4.测试：</p>
<p>多次刷新<a target="_blank" rel="noopener" href="http://localhost/consumer/payment/feign/timeout">http://localhost/consumer/payment/feign/timeout</a></p>
<p>将会跳出错误Spring Boot默认错误页面，主要异常：<code>feign.RetryableException:Read timed out executing GET http://CLOUD-PAYMENT-SERVCE/payment/feign/timeout。</code></p>
<p><strong>OpenFeign默认等待1秒钟，超过后报错</strong></p>
<p><strong>YML文件里需要开启OpenFeign客户端超时控制</strong></p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#设置feign客户端超时时间(OpenFeign默认支持ribbon)(单位：毫秒)</span></span><br><span class="line"><span class="attr">ribbon:</span></span><br><span class="line">  <span class="comment">#指的是建立连接所用的时间，适用于网络状况正常的情况下,两端连接所用的时间</span></span><br><span class="line">  <span class="attr">ReadTimeout:</span> <span class="number">5000</span></span><br><span class="line">  <span class="comment">#指的是建立连接后从服务器读取到可用资源所用的时间</span></span><br><span class="line">  <span class="attr">ConnectTimeout:</span> <span class="number">5000</span></span><br></pre></td></tr></table></figure>

<h4 id="OpenFeign日志增强"><a href="#OpenFeign日志增强" class="headerlink" title="OpenFeign日志增强"></a>OpenFeign日志增强</h4><p><strong>日志打印功能</strong></p>
<p>Feign提供了日志打印功能，我们可以通过配置来调整日恙级别，从而了解Feign 中 Http请求的细节。</p>
<p>说白了就是对Feign接口的调用情况进行监控和输出</p>
<p><strong>日志级别</strong></p>
<ul>
<li>NONE：默认的，不显示任何日志;</li>
<li>BASIC：仅记录请求方法、URL、响应状态码及执行时间;</li>
<li>HEADERS：除了BASIC中定义的信息之外，还有请求和响应的头信息;</li>
<li>FULL：除了HEADERS中定义的信息之外，还有请求和响应的正文及元数据。</li>
</ul>
<p><strong>配置日志bean</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FeignConfig</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    Logger.Level <span class="title function_">feignLoggerLevel</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> Logger.Level.FULL;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>YML文件里需要开启日志的Feign客户端</strong></p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">logging:</span></span><br><span class="line">  <span class="attr">level:</span></span><br><span class="line">    <span class="comment"># feign日志以什么级别监控哪个接口</span></span><br><span class="line">    <span class="attr">com.ljx.springcloud.service.PaymentFeignService:</span> <span class="string">debug</span></span><br></pre></td></tr></table></figure>

<p><strong>后台日志查看</strong></p>
<p>得到更多日志信息</p>
<h2 id="服务降级"><a href="#服务降级" class="headerlink" title="服务降级"></a>服务降级</h2><p><strong>分布式系统面临的问题</strong></p>
<p>复杂分布式体系结构中的应用程序有数十个依赖关系，每个依赖关系在某些时候将不可避免地失败。</p>
<p><strong>服务雪崩</strong></p>
<p>多个微服务之间调用的时候，假设微服务A调用微服务B和微服务C，微服务B和微服务C又调用其它的微服务，这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用，对微服务A的调用就会占用越来越多的系统资源，进而引起系统崩溃，所谓的“雪崩效应”.<br>对于高流量的应用来说，单一的后避依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是，这些应用程序还可能导致服务之间的延迟增加，备份队列，线程和其他系统资源紧张，导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理，以便单个依赖关系的失败，不能取消整个应用程序或系统。</p>
<p>所以，通常当你发现一个模块下的某个实例失败后，这时候这个模块依然还会接收流量，然后这个有问题的模块还调用了其他的模块，这样就会发生级联故障，或者叫雪崩。</p>
<h3 id="Hystrix"><a href="#Hystrix" class="headerlink" title="Hystrix"></a>Hystrix</h3><p>Hystrix是一个用于处理分布式系统的延迟和容错的开源库，在分布式系统里，许多依赖不可避免的会调用失败，比如超时、异常等，Hystrix能够保证在一个依赖出问题的情况下，不会导致整体服务失败，避免级联故障，以提高分布式系统的弹性。</p>
<p>“断路器”本身是一种开关装置，当某个服务单元发生故障之后，通过断路器的故障监控（类似熔断保险丝)，向调用方返回一个符合预期的、可处理的备选响应（FallBack)，而不是长时间的等待或者抛出调用方无法处理的异常，这样就保证了服务调用方的线程不会被长时间、不必要地占用，从而避免了故障在分布式系统中的蔓延，乃至雪崩。</p>
<p><strong>主要功能</strong></p>
<ul>
<li>服务降级</li>
<li>服务熔断</li>
<li>接近实对的监控</li>
</ul>
<p><strong>服务降级</strong></p>
<p>服务器忙，请稍后再试，不让客户端等待并立刻返回一个友好提示，fallback</p>
<p>哪些情况会出发降级？</p>
<ul>
<li><p>程序运行导常</p>
</li>
<li><p>超时</p>
</li>
<li><p>服务熔断触发服务降级</p>
</li>
<li><p>线程池&#x2F;信号量打满也会导致服务降级</p>
</li>
</ul>
<p><strong>服务熔断</strong></p>
<p>类比保险丝达到最大服务访问后，直接拒绝访问，拉闸限电，然后调用服务降级的方法并返回友好提示。</p>
<p>服务的降级 -&gt; 进而熔断 -&gt; 恢复调用链路</p>
<p><strong>服务限流</strong></p>
<p>秒杀高并发等操作，严禁一窝蜂的过来拥挤，大家排队，一秒钟N个，有序进行。</p>
<h4 id="Hystrix支付微服务构建"><a href="#Hystrix支付微服务构建" class="headerlink" title="Hystrix支付微服务构建"></a>Hystrix支付微服务构建</h4><p>1.新建cloud-provider-hygtrix-payment8001</p>
<p>2.POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-hystrix<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8001</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloud-provider-hystrix-payment</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">fetch-registry:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka</span></span><br></pre></td></tr></table></figure>

<p>4.主启动</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableEurekaClient</span></span><br></pre></td></tr></table></figure>

<p>5.业务类</p>
<p>service</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentService</span> &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_OK</span><span class="params">(Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;线程池:  &quot;</span>+Thread.currentThread().getName()+<span class="string">&quot;  paymentInfo_OK,id:  &quot;</span>+id+<span class="string">&quot;\t&quot;</span>+<span class="string">&quot;O(∩_∩)O哈哈~&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOut</span><span class="params">(Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123; TimeUnit.MILLISECONDS.sleep(<span class="number">3000</span>); &#125; <span class="keyword">catch</span> (InterruptedException e) &#123; e.printStackTrace(); &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;线程池:  &quot;</span>+Thread.currentThread().getName()+<span class="string">&quot; id:  &quot;</span>+id+<span class="string">&quot;\t&quot;</span>+<span class="string">&quot;O(∩_∩)O哈哈~&quot;</span>+<span class="string">&quot;  耗时(秒): 3&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> PaymentService paymentService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;server.port&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String serverPort;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/payment/hystrix/ok/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_OK</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> paymentService.paymentInfo_OK(id);</span><br><span class="line">        log.info(<span class="string">&quot;*****result: &quot;</span>+result);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/payment/hystrix/timeout/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOut</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> paymentService.paymentInfo_TimeOut(id);</span><br><span class="line">        log.info(<span class="string">&quot;*****result: &quot;</span>+result);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>6.正常测试</p>
<p>以上述为根基平台，从正确 -&gt; 错误 -&gt; 降级熔断 -&gt; 恢复。</p>
<h4 id="JMeter高并发压测后卡顿"><a href="#JMeter高并发压测后卡顿" class="headerlink" title="JMeter高并发压测后卡顿"></a>JMeter高并发压测后卡顿</h4><p><strong>上述在非高并发情形下，还能勉强满足</strong></p>
<p><strong>Jmeter压测结论</strong></p>
<p>上面还是服务提供者8001自己测试，假如此时外部的消费者80也来访问，那消费者只能干等，最终导致消费端80不满意，服务端8001直接被拖慢</p>
<h4 id="Hystrix订单微服务"><a href="#Hystrix订单微服务" class="headerlink" title="Hystrix订单微服务"></a>Hystrix订单微服务</h4><p>1.新建 - cloud-consumer-feign-hystrix-order80</p>
<p>2.POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-hystrix<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka</span></span><br></pre></td></tr></table></figure>

<p>4.主启动</p>
<p>5.业务类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@FeignClient(value = &quot;CLOUD-PROVIDER-HYSTRIX-PAYMENT&quot; /*,fallback = PaymentFallbackService.class*/)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">PaymentHystrixService</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@GetMapping(&quot;/payment/hystrix/ok/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_OK</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/payment/hystrix/timeout/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOut</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderHystirxController</span> &#123;</span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> PaymentHystrixService paymentHystrixService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/consumer/payment/hystrix/ok/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_OK</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> paymentHystrixService.paymentInfo_OK(id);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/consumer/payment/hystrix/timeout/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOut</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> paymentHystrixService.paymentInfo_TimeOut(id);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>6.正常测试</p>
<p>7.高并发测试</p>
<p>2W个线程压8001，消费端80微服务再去访问正常的Ok微服务8001地址，消费者80被拖慢</p>
<p>原因：8001同一层次的其它接口服务被困死，因为tomcat线程池里面的工作线程已经被挤占完毕。</p>
<p>正因为有上述故障或不佳表现才有我们的降级&#x2F;容错&#x2F;限流等技术诞生。</p>
<h4 id="降级容错解决的维度要求"><a href="#降级容错解决的维度要求" class="headerlink" title="降级容错解决的维度要求"></a>降级容错解决的维度要求</h4><p>超时导致服务器变慢(转圈) —》超时不再等待</p>
<p>出错(宕机或程序运行出错) —》 出错要有兜底</p>
<p>解决：</p>
<ul>
<li>对方服务(8001)超时了，调用者(80)不能一直卡死等待，必须有服务降级。</li>
<li>对方服务(8001)down机了，调用者(80)不能一直卡死等待，必须有服务降级。</li>
<li>对方服务(8001)OK，调用者(80)自己出故障或有自我要求(自己的等待时间小于服务提供者)，自己处理降级。</li>
</ul>
<h4 id="Hystrix服务降级支付fallback"><a href="#Hystrix服务降级支付fallback" class="headerlink" title="Hystrix服务降级支付fallback"></a>Hystrix服务降级支付fallback</h4><p>降级配置 - <code>@HystrixCommand</code></p>
<p><strong>设置自身调用超时时间的峰值，峰值内可以正常运行，超过了需要有兜底的方法处埋，作服务降级fallback</strong>。</p>
<p>—旦调用服务方法失败并抛出了错误信息后，会自动调用<code>@HystrixCommand</code>标注好的<code>fallbackMethod</code>调用类中的指定方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentService</span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@HystrixCommand(fallbackMethod = &quot;paymentInfo_TimeOutHandler&quot;, commandProperties = &#123;</span></span><br><span class="line"><span class="meta">            @HystrixProperty(name=&quot;execution.isolation.thread.timeoutInMilliseconds&quot;,value=&quot;3000&quot;)</span></span><br><span class="line"><span class="meta">    &#125;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOut</span><span class="params">(Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//int age = 10/0;</span></span><br><span class="line">        <span class="keyword">try</span> &#123; TimeUnit.MILLISECONDS.sleep(<span class="number">5000</span>); &#125; <span class="keyword">catch</span> (InterruptedException e) &#123; e.printStackTrace(); &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;线程池:  &quot;</span>+Thread.currentThread().getName()+<span class="string">&quot; id:  &quot;</span>+id+<span class="string">&quot;\t&quot;</span>+<span class="string">&quot;O(∩_∩)O哈哈~&quot;</span>+<span class="string">&quot;  耗时(秒): &quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//用来善后的方法</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOutHandler</span><span class="params">(Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;线程池:  &quot;</span>+Thread.currentThread().getName()+<span class="string">&quot;  8001系统繁忙或者运行报错，请稍后再试,id:  &quot;</span>+id+<span class="string">&quot;\t&quot;</span>+<span class="string">&quot;o(╥﹏╥)o&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面故意制造两种异常:</p>
<ol>
<li>int age &#x3D; 10&#x2F;0，计算异常</li>
<li>我们能接受3秒钟，它运行5秒钟，超时异常。</li>
</ol>
<p>当前服务不可用了，做服务降级，兜底的方案都是<code>paymentInfo_TimeOutHandler</code></p>
<p><strong>主启动类激活</strong></p>
<p>添加新注解<code>@EnableCircuitBreaker</code></p>
<h4 id="Hystrix服务降级订单fallback"><a href="#Hystrix服务降级订单fallback" class="headerlink" title="Hystrix服务降级订单fallback"></a>Hystrix服务降级订单fallback</h4><p>1.YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#开启</span></span><br><span class="line"><span class="attr">feign:</span></span><br><span class="line">  <span class="attr">hystrix:</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>

<p>2.主启动添加<code>@EnableHystrix</code></p>
<p>3.业务类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderHystirxController</span> &#123;</span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> PaymentHystrixService paymentHystrixService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/consumer/payment/hystrix/timeout/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="meta">@HystrixCommand(fallbackMethod = &quot;paymentTimeOutFallbackMethod&quot;,commandProperties = &#123;</span></span><br><span class="line"><span class="meta">            @HystrixProperty(name=&quot;execution.isolation.thread.timeoutInMilliseconds&quot;,value=&quot;1500&quot;)</span></span><br><span class="line"><span class="meta">    &#125;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOut</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span> &#123;</span><br><span class="line">        <span class="comment">//int age = 10/0;</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> paymentHystrixService.paymentInfo_TimeOut(id);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//善后方法</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentTimeOutFallbackMethod</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="Hystrix全局服务降级DefaultProperties"><a href="#Hystrix全局服务降级DefaultProperties" class="headerlink" title="Hystrix全局服务降级DefaultProperties"></a>Hystrix全局服务降级DefaultProperties</h4><p><strong>前问题1</strong> 每个业务方法对应一个兜底的方法，代码膨胀</p>
<p><strong>解决方法</strong></p>
<p>1:1每个方法配置一个服务降级方法，技术上可以，但是不聪明</p>
<p>1:N除了个别重要核心业务有专属，其它普通的可以通过<code>@DefaultProperties(defaultFallback = “xxx”)</code>统一跳转到统一处理结果页面</p>
<p>通用的和独享的各自分开，避免了代码膨胀，合理减少了代码量</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@DefaultProperties(defaultFallback = &quot;payment_Global_FallbackMethod&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderHystirxController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> PaymentHystrixService paymentHystrixService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/consumer/payment/hystrix/ok/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_OK</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> paymentHystrixService.paymentInfo_OK(id);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//    @HystrixCommand(fallbackMethod = &quot;paymentTimeOutFallbackMethod&quot;, commandProperties = &#123;</span></span><br><span class="line"><span class="comment">//            @HystrixProperty(name=&quot;execution.isolation.thread.timeoutInMilliseconds&quot;,value=&quot;3000&quot;)</span></span><br><span class="line"><span class="comment">//    &#125;)</span></span><br><span class="line">    <span class="meta">@HystrixCommand</span><span class="comment">//用全局的fallback方法</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/consumer/payment/hystrix/timeout/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOut</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> paymentHystrixService.paymentInfo_TimeOut(id);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//善后方法</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentTimeOutFallbackMethod</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 下面是全局fallback方法</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">payment_Global_FallbackMethod</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Global异常处理信息，请稍后再试，/(ㄒoㄒ)/~~&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="Hystrix通配服务降级FeignFallback"><a href="#Hystrix通配服务降级FeignFallback" class="headerlink" title="Hystrix通配服务降级FeignFallback"></a>Hystrix通配服务降级FeignFallback</h4><p><strong>目前问题2</strong> 统一和自定义的分开，代码混乱</p>
<p><strong>服务降级，客户端去调用服务端，碰上服务端宕机或关闭</strong></p>
<p>本次案例服务降级处理是在客户端80实现完成的，与服务端8001没有关系，只需要为<a target="_blank" rel="noopener" href="https://so.csdn.net/so/search?q=Feign&spm=1001.2101.3001.7020">Feign</a>客户端定义的接口添加一个服务降级处理的实现类即可实现解耦</p>
<p><strong>未来我们要面对的异常</strong></p>
<ul>
<li>运行</li>
<li>超时</li>
<li>宕机</li>
</ul>
<p>1.新建PaymentFallbackService类实现PaymentHystrixService接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentFallbackService</span> <span class="keyword">implements</span> <span class="title class_">PaymentHystrixService</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_OK</span><span class="params">(Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOut</span><span class="params">(Integer id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>2.YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">feign:</span></span><br><span class="line">  <span class="attr">hystrix:</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>

<p>3.PaymentHystrixService接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@FeignClient(value = &quot;CLOUD-PROVIDER-HYSTRIX-PAYMENT&quot; ,</span></span><br><span class="line"><span class="meta">             fallback = PaymentFallbackService.class)</span><span class="comment">//指定PaymentFallbackService类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">PaymentHystrixService</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@GetMapping(&quot;/payment/hystrix/ok/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_OK</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/payment/hystrix/timeout/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo_TimeOut</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>4.测试</p>
<p>单个eureka先启动7001，PaymentHystrixMain8001启动</p>
<p>正常访问测试 - <a target="_blank" rel="noopener" href="http://localhost/consumer/payment/hystrix/ok/1%EF%BC%8C%E6%95%85%E6%84%8F%E5%85%B3%E9%97%AD%E5%BE%AE%E6%9C%8D%E5%8A%A18001">http://localhost/consumer/payment/hystrix/ok/1，故意关闭微服务8001</a></p>
<p>客户端自己调用提示 - 此时服务端provider已经down了，但是我们做了服务降级处理，让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器。</p>
<h4 id="Hystrix服务熔断理论"><a href="#Hystrix服务熔断理论" class="headerlink" title="Hystrix服务熔断理论"></a>Hystrix服务熔断理论</h4><p>断路器，相当于保险丝。</p>
<p><strong>熔断机制概述</strong></p>
<p>熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时，会进行服务的降级，进而熔断该节点微服务的调用，快速返回错误的响应信息。当检测到该节点微服务调用响应正常后，恢复调用链路。</p>
<p>在Spring Cloud框架里，熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况，当失败的调用到一定阈值，缺省是5秒内20次调用失败，就会启动熔断机制，只有当成功率挺高到一定阈值才会关闭。熔断机制的注解是<code>@HystrixCommand</code>。</p>
<h4 id="Hystrix之服务熔断案例"><a href="#Hystrix之服务熔断案例" class="headerlink" title="Hystrix之服务熔断案例"></a>Hystrix之服务熔断案例</h4><p><a target="_blank" rel="noopener" href="https://hutool.cn/">Hutool国产工具类</a></p>
<p>修改cloud-provider-hystrix-payment8001</p>
<p>service层</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentService</span>&#123;    </span><br><span class="line">   </span><br><span class="line">    <span class="comment">//=====服务熔断</span></span><br><span class="line">    <span class="meta">@HystrixCommand(fallbackMethod = &quot;paymentCircuitBreaker_fallback&quot;,commandProperties = &#123;</span></span><br><span class="line"><span class="meta">            @HystrixProperty(name = &quot;circuitBreaker.enabled&quot;,value = &quot;true&quot;),// 是否开启断路器</span></span><br><span class="line"><span class="meta">            @HystrixProperty(name = &quot;circuitBreaker.requestVolumeThreshold&quot;,value = &quot;10&quot;),// 请求次数</span></span><br><span class="line"><span class="meta">            @HystrixProperty(name = &quot;circuitBreaker.sleepWindowInMilliseconds&quot;,value = &quot;10000&quot;), // 时间窗口期</span></span><br><span class="line"><span class="meta">            @HystrixProperty(name = &quot;circuitBreaker.errorThresholdPercentage&quot;,value = &quot;60&quot;),// 失败率达到多少后跳闸</span></span><br><span class="line"><span class="meta">    &#125;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentCircuitBreaker</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span>(id &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(<span class="string">&quot;******id 不能负数&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">String</span> <span class="variable">serialNumber</span> <span class="operator">=</span> IdUtil.simpleUUID();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> Thread.currentThread().getName()+<span class="string">&quot;\t&quot;</span>+<span class="string">&quot;调用成功，流水号: &quot;</span> + serialNumber;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentCircuitBreaker_fallback</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;id 不能负数，请稍后再试，/(ㄒoㄒ)/~~   id: &quot;</span> +id;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>controller层</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/payment/circuit/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">paymentCircuitBreaker</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> paymentService.paymentCircuitBreaker(id);</span><br><span class="line">    log.info(<span class="string">&quot;****result: &quot;</span>+result);</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>测试</strong></p>
<p>多次错误，再来次正确，但错误得显示</p>
<p>重点测试 - 多次错误，然后慢慢正确，发现刚开始不满足条件，就算是正确的访问地址也不能进行</p>
<h4 id="Hystrix服务熔断总结"><a href="#Hystrix服务熔断总结" class="headerlink" title="Hystrix服务熔断总结"></a>Hystrix服务熔断总结</h4><p><strong>熔断类型</strong></p>
<ul>
<li>熔断打开：请求不再进行调用当前服务，内部设置时钟一般为MTTR(平均故障处理时间)，当打开时长达到所设时钟则进入半熔断状态。</li>
<li>熔断关闭：熔断关闭不会对服务进行熔断。</li>
<li>熔断半开：部分请求根据规则调用当前服务，如果请求成功且符合规则则认为当前服务恢复正常，关闭熔断。</li>
</ul>
<p><strong>断路器开启或者关闭的条件</strong></p>
<ul>
<li>到达以下阀值，断路器将会开启：<ul>
<li>当满足一定的阀值的时候（默认10秒内超过20个请求次数)</li>
<li>当失败率达到一定的时候（默认10秒内超过50%的请求失败)</li>
</ul>
</li>
<li>当开启的时候，所有请求都不会进行转发</li>
<li>一段时间之后（默认是5秒)，这个时候断路器是半开状态，会让其中一个请求进行转发。如果成功，断路器会关闭，若失败，继续开启。</li>
</ul>
<p><strong>断路器打开之后</strong></p>
<p>1：再有请求调用的时候，将不会调用主逻辑，而是直接调用降级fallback。通过断路器，实现了自动地发现错误并将降级逻辑切换为主逻辑，减少响应延迟的效果。</p>
<p>2：原来的主逻辑要如何恢复呢？</p>
<p>对于这一问题，hystrix也为我们实现了自动恢复功能。</p>
<p>当断路器打开，对主逻辑进行熔断之后，hystrix会启动一个休眠时间窗，在这个时间窗内，降级逻辑是临时的成为主逻辑，当休眠时间窗到期，断路器将进入半开状态，释放一次请求到原来的主逻辑上，如果此次请求正常返回，那么断路器将继续闭合，主逻辑恢复，如果这次请求依然有问题，断路器继续进入打开状态，休眠时间窗重新计时。</p>
<p><strong>All配置</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@HystrixCommand(fallbackMethod = &quot;fallbackMethod&quot;, </span></span><br><span class="line"><span class="meta">                groupKey = &quot;strGroupCommand&quot;, </span></span><br><span class="line"><span class="meta">                commandKey = &quot;strCommand&quot;, </span></span><br><span class="line"><span class="meta">                threadPoolKey = &quot;strThreadPool&quot;,</span></span><br><span class="line"><span class="meta">                </span></span><br><span class="line"><span class="meta">                commandProperties = &#123;</span></span><br><span class="line"><span class="meta">                    // 设置隔离策略，THREAD 表示线程池 SEMAPHORE：信号池隔离</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;execution.isolation.strategy&quot;, value = &quot;THREAD&quot;),</span></span><br><span class="line"><span class="meta">                    // 当隔离策略选择信号池隔离的时候，用来设置信号池的大小（最大并发数）</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;execution.isolation.semaphore.maxConcurrentRequests&quot;, value = &quot;10&quot;),</span></span><br><span class="line"><span class="meta">                    // 配置命令执行的超时时间</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;execution.isolation.thread.timeoutinMilliseconds&quot;, value = &quot;10&quot;),</span></span><br><span class="line"><span class="meta">                    // 是否启用超时时间</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;execution.timeout.enabled&quot;, value = &quot;true&quot;),</span></span><br><span class="line"><span class="meta">                    // 执行超时的时候是否中断</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;execution.isolation.thread.interruptOnTimeout&quot;, value = &quot;true&quot;),</span></span><br><span class="line"><span class="meta">                    </span></span><br><span class="line"><span class="meta">                    // 执行被取消的时候是否中断</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;execution.isolation.thread.interruptOnCancel&quot;, value = &quot;true&quot;),</span></span><br><span class="line"><span class="meta">                    // 允许回调方法执行的最大并发数</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;fallback.isolation.semaphore.maxConcurrentRequests&quot;, value = &quot;10&quot;),</span></span><br><span class="line"><span class="meta">                    // 服务降级是否启用，是否执行回调函数</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;fallback.enabled&quot;, value = &quot;true&quot;),</span></span><br><span class="line"><span class="meta">                    // 是否启用断路器</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;circuitBreaker.enabled&quot;, value = &quot;true&quot;),</span></span><br><span class="line"><span class="meta">                    // 该属性用来设置在滚动时间窗中，断路器熔断的最小请求数。例如，默认该值为 20 的时候，如果滚动时间窗（默认10秒）内仅收到了19个请求， 即使这19个请求都失败了，断路器也不会打开。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;circuitBreaker.requestVolumeThreshold&quot;, value = &quot;20&quot;),</span></span><br><span class="line"><span class="meta">                    </span></span><br><span class="line"><span class="meta">                    // 该属性用来设置在滚动时间窗中，表示在滚动时间窗中，在请求数量超过 circuitBreaker.requestVolumeThreshold 的情况下，如果错误请求数的百分比超过50, 就把断路器设置为 &quot;打开&quot; 状态，否则就设置为 &quot;关闭&quot; 状态。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;circuitBreaker.errorThresholdPercentage&quot;, value = &quot;50&quot;),</span></span><br><span class="line"><span class="meta">                    // 该属性用来设置当断路器打开之后的休眠时间窗。 休眠时间窗结束之后，会将断路器置为 &quot;半开&quot; 状态，尝试熔断的请求命令，如果依然失败就将断路器继续设置为 &quot;打开&quot; 状态，如果成功就设置为 &quot;关闭&quot; 状态。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;circuitBreaker.sleepWindowinMilliseconds&quot;, value = &quot;5000&quot;),</span></span><br><span class="line"><span class="meta">                    // 断路器强制打开</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;circuitBreaker.forceOpen&quot;, value = &quot;false&quot;),</span></span><br><span class="line"><span class="meta">                    // 断路器强制关闭</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;circuitBreaker.forceClosed&quot;, value = &quot;false&quot;),</span></span><br><span class="line"><span class="meta">                    // 滚动时间窗设置，该时间用于断路器判断健康度时需要收集信息的持续时间</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;metrics.rollingStats.timeinMilliseconds&quot;, value = &quot;10000&quot;),</span></span><br><span class="line"><span class="meta">                    </span></span><br><span class="line"><span class="meta">                    // 该属性用来设置滚动时间窗统计指标信息时划分&quot;桶&quot;的数量，断路器在收集指标信息的时候会根据设置的时间窗长度拆分成多个 &quot;桶&quot; 来累计各度量值，每个&quot;桶&quot;记录了一段时间内的采集指标。</span></span><br><span class="line"><span class="meta">                    // 比如 10 秒内拆分成 10 个&quot;桶&quot;收集这样，所以 timeinMilliseconds 必须能被 numBuckets 整除。否则会抛异常</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;metrics.rollingStats.numBuckets&quot;, value = &quot;10&quot;),</span></span><br><span class="line"><span class="meta">                    // 该属性用来设置对命令执行的延迟是否使用百分位数来跟踪和计算。如果设置为 false, 那么所有的概要统计都将返回 -1。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;metrics.rollingPercentile.enabled&quot;, value = &quot;false&quot;),</span></span><br><span class="line"><span class="meta">                    // 该属性用来设置百分位统计的滚动窗口的持续时间，单位为毫秒。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;metrics.rollingPercentile.timeInMilliseconds&quot;, value = &quot;60000&quot;),</span></span><br><span class="line"><span class="meta">                    // 该属性用来设置百分位统计滚动窗口中使用 “ 桶 ”的数量。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;metrics.rollingPercentile.numBuckets&quot;, value = &quot;60000&quot;),</span></span><br><span class="line"><span class="meta">                    // 该属性用来设置在执行过程中每个 “桶” 中保留的最大执行次数。如果在滚动时间窗内发生超过该设定值的执行次数，</span></span><br><span class="line"><span class="meta">                    // 就从最初的位置开始重写。例如，将该值设置为100, 滚动窗口为10秒，若在10秒内一个 “桶 ”中发生了500次执行，</span></span><br><span class="line"><span class="meta">                    // 那么该 “桶” 中只保留 最后的100次执行的统计。另外，增加该值的大小将会增加内存量的消耗，并增加排序百分位数所需的计算时间。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;metrics.rollingPercentile.bucketSize&quot;, value = &quot;100&quot;),</span></span><br><span class="line"><span class="meta">                    </span></span><br><span class="line"><span class="meta">                    // 该属性用来设置采集影响断路器状态的健康快照（请求的成功、 错误百分比）的间隔等待时间。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;metrics.healthSnapshot.intervalinMilliseconds&quot;, value = &quot;500&quot;),</span></span><br><span class="line"><span class="meta">                    // 是否开启请求缓存</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;requestCache.enabled&quot;, value = &quot;true&quot;),</span></span><br><span class="line"><span class="meta">                    // HystrixCommand的执行和事件是否打印日志到 HystrixRequestLog 中</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;requestLog.enabled&quot;, value = &quot;true&quot;),</span></span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">                &#125;,</span></span><br><span class="line"><span class="meta">                threadPoolProperties = &#123;</span></span><br><span class="line"><span class="meta">                    // 该参数用来设置执行命令线程池的核心线程数，该值也就是命令执行的最大并发量</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;coreSize&quot;, value = &quot;10&quot;),</span></span><br><span class="line"><span class="meta">                    // 该参数用来设置线程池的最大队列大小。当设置为 -1 时，线程池将使用 SynchronousQueue 实现的队列，否则将使用 LinkedBlockingQueue 实现的队列。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;maxQueueSize&quot;, value = &quot;-1&quot;),</span></span><br><span class="line"><span class="meta">                    // 该参数用来为队列设置拒绝阈值。 通过该参数， 即使队列没有达到最大值也能拒绝请求。</span></span><br><span class="line"><span class="meta">                    // 该参数主要是对 LinkedBlockingQueue 队列的补充,因为 LinkedBlockingQueue 队列不能动态修改它的对象大小，而通过该属性就可以调整拒绝请求的队列大小了。</span></span><br><span class="line"><span class="meta">                    @HystrixProperty(name = &quot;queueSizeRejectionThreshold&quot;, value = &quot;5&quot;),</span></span><br><span class="line"><span class="meta">                &#125;</span></span><br><span class="line"><span class="meta">               )</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">doSomething</span><span class="params">()</span> &#123;</span><br><span class="line">	...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="Hystrix图形化Dashboard搭建"><a href="#Hystrix图形化Dashboard搭建" class="headerlink" title="Hystrix图形化Dashboard搭建"></a>Hystrix图形化Dashboard搭建</h4><p><strong>概述</strong></p>
<p>除了隔离依赖服务的调用以外，Hystrix还提供了准实时的调用监控(Hystrix Dashboard)，Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息，并以统计报表和图形的形式展示给用户，包括每秒执行多少请求多少成功，多少失败等。</p>
<p>Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合，对监控内容转化成可视化界面。</p>
<p><strong>仪表盘9001</strong></p>
<p>1新建cloud-consumer-hystrix-dashboard9001</p>
<p>2.POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-hystrix-dashboard<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">9001</span></span><br></pre></td></tr></table></figure>

<p>4.HystrixDashboardMain9001+新注解<code>@EnableHystrixDashboard</code></p>
<p>5.所有Provider微服务提供类(8001&#x2F;8002&#x2F;8003)都需要监控依赖配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>6.浏览器输入<a target="_blank" rel="noopener" href="http://localhost:9001/hystrix">http://localhost:9001/hystrix</a></p>
<h4 id="Hystrix图形化Dashboard监控实战"><a href="#Hystrix图形化Dashboard监控实战" class="headerlink" title="Hystrix图形化Dashboard监控实战"></a>Hystrix图形化Dashboard监控实战</h4><p><strong>修改cloud-provider-hystrix-payment8001</strong></p>
<p>注意：新版本Hystrix需要在主启动类PaymentHystrixMain8001中指定监控路径</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@EnableCircuitBreaker</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentHystrixMain8001</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">            SpringApplication.run(PaymentHystrixMain8001.class, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *此配置是为了服务监控而配置，与服务容错本身无关，springcloud升级后的坑</span></span><br><span class="line"><span class="comment">     *ServletRegistrationBean因为springboot的默认路径不是&quot;/hystrix.stream&quot;，</span></span><br><span class="line"><span class="comment">     *只要在自己的项目里配置上下面的servlet就可以了</span></span><br><span class="line"><span class="comment">     *否则，Unable to connect to Command Metric Stream 404</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> ServletRegistrationBean <span class="title function_">getServlet</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">HystrixMetricsStreamServlet</span> <span class="variable">streamServlet</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HystrixMetricsStreamServlet</span>();</span><br><span class="line">        <span class="type">ServletRegistrationBean</span> <span class="variable">registrationBean</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ServletRegistrationBean</span>(streamServlet);</span><br><span class="line">        registrationBean.setLoadOnStartup(<span class="number">1</span>);</span><br><span class="line">        registrationBean.addUrlMappings(<span class="string">&quot;/hystrix.stream&quot;</span>);</span><br><span class="line">        registrationBean.setName(<span class="string">&quot;HystrixMetricsStreamServlet&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> registrationBean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>监控测试</strong></p>
<p>启动1个eureka</p>
<p>启动8001，9001</p>
<p><strong>观察监控窗口</strong></p>
<p>9001监控8001 - 填写监控地址 - <a target="_blank" rel="noopener" href="http://localhost:8001/hystrix.stream">http://localhost:8001/hystrix.stream</a> 到 <a target="_blank" rel="noopener" href="http://localhost:9001/hystrix%E9%A1%B5%E9%9D%A2%E7%9A%84%E8%BE%93%E5%85%A5%E6%A1%86%E3%80%82">http://localhost:9001/hystrix页面的输入框。</a></p>
<p>测试地址</p>
<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:8001/payment/circuit/1">http://localhost:8001/payment/circuit/1</a></li>
<li><a target="_blank" rel="noopener" href="http://localhost:8001/payment/circuit/-1">http://localhost:8001/payment/circuit/-1</a></li>
<li>测试通过</li>
<li>先访问正确地址，再访问错误地址，再正确地址，会发现图示断路器都是慢慢放开的。</li>
</ul>
<h2 id="服务网关"><a href="#服务网关" class="headerlink" title="服务网关"></a>服务网关</h2><h3 id="GateWay"><a href="#GateWay" class="headerlink" title="GateWay"></a>GateWay</h3><p><strong>概述</strong></p>
<p>Cloud全家桶中有个很重要的组件就是网关，在1.x版本中都是采用的Zuul网关;</p>
<p>但在2.x版本中，zuul的升级一直跳票，SpringCloud最后自己研发了一个网关替代Zuul，那就是SpringCloud Gateway—句话：gateway是原zuul1.x版的替代</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/54b61d819aa1630bc61732de340b55b4.png" alt="axh25f.png"></p>
<p>Gateway是在Spring生态系统之上构建的API网关服务，基于Spring 5，Spring Boot 2和Project Reactor等技术。</p>
<p><strong>SpringCloud Gateway是基于WebFlux框架实现的，而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty</strong>。</p>
<p><strong>作用</strong></p>
<ul>
<li>方向代理</li>
<li>鉴权</li>
<li>流量控制</li>
<li>熔断</li>
<li>日志监控</li>
<li>…</li>
</ul>
<p><strong>微服务架构中网关的位置</strong></p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/5877d4b9035ead9cd2d037609dceb442.png" alt="asd14667.png"></p>
<h4 id="Gateway工作流程"><a href="#Gateway工作流程" class="headerlink" title="Gateway工作流程"></a><strong>Gateway工作流程</strong></h4><p><strong>三大核心概念</strong></p>
<ul>
<li>Route(路由) - 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由；</li>
<li>Predicate(断言) - 参考的是Java8的java.util.function.Predicate，开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由；</li>
<li>Filter(过滤) - 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。</li>
</ul>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/62be54501c6e2b95620b79cc918a2e9a.png" alt="d1c.png"></p>
<p>客户端向Spring Cloud Gateway发出请求。然后在Gateway Handler Mapping 中找到与请求相匹配的路由，将其发送到GatewayWeb Handler。</p>
<p>Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑，然后返回。</p>
<p>过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”）执行业务逻辑。</p>
<p>Filter在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等，在“post”类型的过滤器中可以做响应内容、响应头的修改，日志的输出，流量监控等有着非常重要的作用。</p>
<p>核心逻辑：<strong>路由转发 + 执行过滤器链</strong>。</p>
<h4 id="Gateway9527搭建"><a href="#Gateway9527搭建" class="headerlink" title="Gateway9527搭建"></a>Gateway9527搭建</h4><p>1.新建Mod	ule - cloud-gateway-gateway9527</p>
<p>2.POM</p>
<p>4.业务类 无</p>
<p>5.主启动类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">GateWayMain9527</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        SpringApplication.run(GateWayMain9527.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们目前不想暴露8001端口，希望在8001外面套一层9527</p>
<p>7.YML新增网关配置</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">9527</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloud-gateway</span></span><br><span class="line"><span class="comment">#############################新增网关配置###########################</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">gateway:</span></span><br><span class="line">      <span class="attr">routes:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">payment_routh</span> <span class="comment">#payment_route    #路由的ID，没有固定规则但要求唯一，建议配合服务名</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">http://localhost:8001</span>          <span class="comment">#匹配后提供服务的路由地址</span></span><br><span class="line">          <span class="comment">#uri: lb://cloud-payment-service #匹配后提供服务的路由地址</span></span><br><span class="line">          <span class="attr">predicates:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">Path=/payment/get/**</span>         <span class="comment"># 断言，路径相匹配的进行路由</span></span><br><span class="line"></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">payment_routh2</span> <span class="comment">#payment_route    #路由的ID，没有固定规则但要求唯一，建议配合服务名</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">http://localhost:8001</span>          <span class="comment">#匹配后提供服务的路由地址</span></span><br><span class="line">          <span class="comment">#uri: lb://cloud-payment-service #匹配后提供服务的路由地址</span></span><br><span class="line">          <span class="attr">predicates:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">Path=/payment/lb/**</span>         <span class="comment"># 断言，路径相匹配的进行路由</span></span><br><span class="line"><span class="comment">####################################################################</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">cloud-gateway-service</span></span><br><span class="line">  <span class="attr">client:</span> <span class="comment">#服务提供者provider注册进eureka服务列表内</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line">      <span class="attr">fetch-registry:</span> <span class="literal">true</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka</span></span><br></pre></td></tr></table></figure>

<p>8.测试</p>
<p>启动7001，启动8001-cloud-provider-payment8001，启动9527网关</p>
<p>访问说明</p>
<ul>
<li>添加网关前 - <a target="_blank" rel="noopener" href="http://localhost:8001/payment/get/1">http://localhost:8001/payment/get/1</a></li>
<li>添加网关后 - <a target="_blank" rel="noopener" href="http://localhost:9527/payment/get/1">http://localhost:9527/payment/get/1</a></li>
<li>两者访问成功，返回相同结果（可以通过9527端口访问8001端口接口）</li>
</ul>
<h4 id="Gateway配置路由的两种方式"><a href="#Gateway配置路由的两种方式" class="headerlink" title="Gateway配置路由的两种方式"></a>Gateway配置路由的两种方式</h4><p><strong>1.在配置文件yml中配置，见上一章节</strong></p>
<p><strong>2.代码中注入RouteLocator的Bean</strong></p>
<p>cloud-gateway-gateway9527业务实现</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">GateWayConfig</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> RouteLocator <span class="title function_">customRouteLocator</span><span class="params">(RouteLocatorBuilder routeLocatorBuilder)</span></span><br><span class="line">    &#123;</span><br><span class="line">        RouteLocatorBuilder.<span class="type">Builder</span> <span class="variable">routes</span> <span class="operator">=</span> routeLocatorBuilder.routes();</span><br><span class="line"></span><br><span class="line">        routes.route(<span class="string">&quot;path_route_ljx&quot;</span>,</span><br><span class="line">                r -&gt; r.path(<span class="string">&quot;&quot;</span>)</span><br><span class="line">                        .uri(<span class="string">&quot;https://www.baidu.com&quot;</span>)).build();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> routes.build();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>浏览器输入<a href="http://localhost:9527，返回https://www.baidu.com相同的页面。">http://localhost:9527，返回https://www.baidu.com相同的页面。</a></p>
<h4 id="GateWay配置动态路由"><a href="#GateWay配置动态路由" class="headerlink" title="GateWay配置动态路由"></a>GateWay配置动态路由</h4><p>默认情况下Gateway会根据注册中心注册的服务列表，以注册中心上微服务名为路径创建<strong>动态路由进行转发，从而实现动态路由的功能</strong>（不写死一个地址）</p>
<p><strong>POM</strong></p>
<p> cloud-gateway-gateway9527的POM中添加</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--eureka-client--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>YML</strong></p>
<p>需要注意的是uri的协议为lb，表示启用Gateway的负载均衡功能。</p>
<p>lb:&#x2F;&#x2F;serviceName是spring cloud gateway在微服务中自动为我们创建的负载均衡uri。</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">9527</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloud-gateway</span></span><br><span class="line"><span class="comment">#############################新增网关配置###########################</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">gateway:</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">locator:</span></span><br><span class="line">          <span class="attr">enabled:</span> <span class="literal">true</span> <span class="comment">#开启从注册中心动态创建路由的功能，利用微服务名进行路由</span></span><br><span class="line">      <span class="attr">routes:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">payment_routh</span> <span class="comment">#payment_route    #路由的ID，没有固定规则但要求唯一，建议配合服务名</span></span><br><span class="line">          <span class="comment">#uri: http://localhost:8001          #匹配后提供服务的路由地址</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">lb://cloud-payment-service</span> <span class="comment">#匹配后提供服务的路由地址</span></span><br><span class="line">          <span class="attr">predicates:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">Path=/payment/get/**</span>         <span class="comment"># 断言，路径相匹配的进行路由</span></span><br><span class="line"></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">payment_routh2</span> <span class="comment">#payment_route    #路由的ID，没有固定规则但要求唯一，建议配合服务名</span></span><br><span class="line">          <span class="comment">#uri: http://localhost:8001          #匹配后提供服务的路由地址</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">lb://cloud-payment-service</span> <span class="comment">#匹配后提供服务的路由地址</span></span><br><span class="line">          <span class="attr">predicates:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">Path=/payment/lb/**</span>         <span class="comment"># 断言，路径相匹配的进行路由</span></span><br><span class="line"><span class="comment">####################################################################</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">cloud-gateway-service</span></span><br><span class="line">  <span class="attr">client:</span> <span class="comment">#服务提供者provider注册进eureka服务列表内</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line">      <span class="attr">fetch-registry:</span> <span class="literal">true</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka</span></span><br></pre></td></tr></table></figure>

<p><strong>测试</strong></p>
<p>浏览器输入 - <a target="_blank" rel="noopener" href="http://localhost:9527/payment/lb">http://localhost:9527/payment/lb</a></p>
<p>不停刷新页面，8001&#x2F;8002两个端口切换。</p>
<h4 id="GateWay常用的Predicate"><a href="#GateWay常用的Predicate" class="headerlink" title="GateWay常用的Predicate"></a>GateWay常用的Predicate</h4><p><strong>常用的Route Predicate Factory</strong></p>
<p>The After Route Predicate Factory<br>The Before Route Predicate Factory<br>The Between Route Predicate Factory<br>The Cookie Route Predicate Factory<br>The Header Route Predicate Factory<br>The Host Route Predicate Factory<br>The Method Route Predicate Factory<br>The Path Route Predicate Factory<br>The Query Route Predicate Factory<br>The RemoteAddr Route Predicate Factory<br>The weight Route Predicate Factory</p>
<p><strong>The After Route Predicate Factory</strong></p>
<p><strong>作用：只有在规定的时间之后启动才能生效</strong></p>
<p>在yml中添加</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">gateway:</span></span><br><span class="line">      <span class="attr">routes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">after_route</span></span><br><span class="line">        <span class="attr">uri:</span> <span class="string">lb://cloud-payment-service</span></span><br><span class="line">        <span class="attr">predicates:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">Path=/payment/get/**</span>      </span><br><span class="line">        <span class="comment"># 这个时间后才能起效</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">After=2023-08-02T14:59:26.090582100+08:00[Asia/Shanghai]</span></span><br></pre></td></tr></table></figure>

<p>可以通过下述方法获得上述格式的时间戳字符串</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ZonedDateTime</span> <span class="variable">zbj</span> <span class="operator">=</span> ZonedDateTime.now(); <span class="comment">// 默认时区</span></span><br><span class="line">System.out.println(zbj);</span><br></pre></td></tr></table></figure>

<p><strong>The Between Route Predicate Factory</strong></p>
<p><strong>作用：只有在规定的时间范围内启动才生效</strong></p>
<p>在yml中添加</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">gateway:</span></span><br><span class="line">      <span class="attr">routes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">between_route</span></span><br><span class="line">        <span class="attr">uri:</span> <span class="string">lb://cloud-payment-service</span></span><br><span class="line">        <span class="comment"># 两个时间点之间</span></span><br><span class="line">        <span class="attr">predicates:</span></span><br><span class="line">         <span class="bullet">-</span> <span class="string">Path=/payment/get/**</span>   </span><br><span class="line">        <span class="bullet">-</span> <span class="string">Between=2024-01-20T17:42:47.789-07:00[America/Denver],</span> <span class="number">2023-08-02T14:59:26.090582100+08:00</span>[<span class="string">Asia/Shanghai</span>]</span><br></pre></td></tr></table></figure>

<p><strong>The Cookie Route Predicate Factory</strong></p>
<p>作用：<strong>只有带username&#x3D;ljx的cookie的请求才有效</strong></p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">gateway:</span></span><br><span class="line">      <span class="attr">routes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">cookie_route</span></span><br><span class="line">        <span class="attr">uri:</span> <span class="string">lb://cloud-payment-service</span></span><br><span class="line">        <span class="attr">predicates:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">Cookie=username,ljx</span></span><br></pre></td></tr></table></figure>

<p><strong>he Header Route Predicate Factory</strong></p>
<p>作用：只有带X-Request-Id&#x3D;正整数的请求头才有效</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">gateway:</span></span><br><span class="line">      <span class="attr">routes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">header_route</span></span><br><span class="line">        <span class="attr">uri:</span> <span class="string">lb://cloud-payment-service</span></span><br><span class="line">        <span class="attr">predicates:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">Header=X-Request-Id,</span> <span class="string">\d+</span></span><br></pre></td></tr></table></figure>

<p><strong>小结</strong></p>
<p>Predicate就是为了实现一组匹配规则，让请求过来找到对应的Route进行处理。</p>
<h4 id="GateWay的Filter"><a href="#GateWay的Filter" class="headerlink" title="GateWay的Filter"></a>GateWay的Filter</h4><p>路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应，路由过滤器只能指定路由进行使用。Spring Cloud Gateway内置了多种路由过滤器，他们都由GatewayFilter的工厂类来产生。</p>
<p>Spring Cloud Gateway的Filter:</p>
<ul>
<li>生命周期：<ul>
<li>pre</li>
<li>post</li>
</ul>
</li>
<li>种类（具体看官方文档）：<ul>
<li>GatewayFilter - 有31种</li>
<li>GlobalFilter - 有10种</li>
</ul>
</li>
</ul>
<p>常用的GatewayFilter：<code>AddRequestParameter</code>，<code>GatewayFilter</code></p>
<p>自定义全局GlobalFilter：</p>
<p>两个主要接口介绍：</p>
<ol>
<li><code>GlobalFilter</code></li>
<li><code>Ordered</code></li>
</ol>
<p>能干什么：</p>
<ol>
<li>全局日志记录</li>
<li>统一网关鉴权</li>
<li>…</li>
</ol>
<p>代码案例：</p>
<p>GateWay9527项目添加MyLogGateWayFilter类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyLogGateWayFilter</span> <span class="keyword">implements</span> <span class="title class_">GlobalFilter</span>,Ordered</span><br><span class="line">&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Mono&lt;Void&gt; <span class="title function_">filter</span><span class="params">(ServerWebExchange exchange, GatewayFilterChain chain)</span></span><br><span class="line">    &#123;</span><br><span class="line">        log.info(<span class="string">&quot;***********come in MyLogGateWayFilter:  &quot;</span>+<span class="keyword">new</span> <span class="title class_">Date</span>());</span><br><span class="line">        <span class="comment">// 处理只有带了uname的请求才能通过</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">uname</span> <span class="operator">=</span> exchange.getRequest().getQueryParams().getFirst(<span class="string">&quot;uname&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span>(uname == <span class="literal">null</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            log.info(<span class="string">&quot;*******用户名为null，非法用户，o(╥﹏╥)o&quot;</span>);</span><br><span class="line">            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);</span><br><span class="line">            <span class="keyword">return</span> exchange.getResponse().setComplete();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> chain.filter(exchange);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getOrder</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试，浏览器输入：</p>
<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:9527/payment/lb">http://localhost:9527/payment/lb</a> - 反问异常</li>
<li><a target="_blank" rel="noopener" href="http://localhost:9527/payment/lb?uname=abc">http://localhost:9527/payment/lb?uname=abc</a> - 正常反问</li>
</ul>
<h2 id="服务配置"><a href="#服务配置" class="headerlink" title="服务配置"></a>服务配置</h2><h3 id="config"><a href="#config" class="headerlink" title="config"></a>config</h3><h4 id="Config分布式配置中心介绍"><a href="#Config分布式配置中心介绍" class="headerlink" title="Config分布式配置中心介绍"></a>Config分布式配置中心介绍</h4><p><strong>分布式系统面临的配置问题</strong></p>
<p>微服务意味着要将单体应用中的业务拆分成一个个子服务，每个服务的粒度相对较小，因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行，所以一套集中式的、动态的配置管理设施是必不可少的。</p>
<p>SpringCloud提供了ConfigServer来解决这个问题，我们每一个微服务自己带着一个application.yml，上百个配置文件的管理.……</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/d5462e3b8c3a063561f5f8fc7fde327e.png" alt="dsaxcj1.png">**</p>
<p>SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持，配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。</p>
<p>SpringCloud Config分为<strong>服务端</strong>和客户端两部分。</p>
<ul>
<li><p>服务端也称为分布式配置中心，它是一个独立的微服务应用，用来连接配置服务器并为客户端提供获取配置信息，加密&#x2F;解密信息等访问接口。</p>
</li>
<li><p>客户端则是通过指定的配置中心来管理应用资源，以及与业务相关的配置内容，并在启动的时候从配置中心获取和加载配置信息配置服务器默认采用git来存储配置信息，这样就有助于对环境配置进行版本管理，并且可以通过git客户端工具来方便的管理和访问配置内容。</p>
</li>
</ul>
<p><strong>能干嘛</strong></p>
<ul>
<li>集中管理配置文件</li>
<li>不同环境不同配置，动态化的配置更新，分环境部署比如dev&#x2F;test&#x2F;prod&#x2F;beta&#x2F;release</li>
<li>运行期间动态调整配置，不再需要在每个服务部署的机器上编写配置文件，服务会向配置中心统一拉取配置自己的信息</li>
<li>当配置发生变动时，服务不需要重启即可感知到配置的变化并应用新的配置</li>
<li>将配置信息以REST接口的形式暴露 - post&#x2F;crul访问刷新即可…</li>
</ul>
<p><strong>与GitHub整合配置</strong></p>
<p>由于SpringCloud Config默认使用Git来存储配置文件(也有其它方式,比如支持SVN和本地文件)，但最推荐的还是Git，而且使用的是http&#x2F;https访问的形式。</p>
<h4 id="Config配置总控中心搭建"><a href="#Config配置总控中心搭建" class="headerlink" title="Config配置总控中心搭建"></a>Config配置总控中心搭建</h4><p>用你自己的账号在GitHub上新建一个名为springcloud-config的新Repository。</p>
<p>由上一步获得刚新建的git地址 - <code>git@github.com:abc/springcloud-config.git</code>。</p>
<p>本地硬盘目录上新建git仓库并clone。</p>
<ul>
<li>工作目录为D:\SpringCloud2021</li>
<li><code>git clone git@github.com:abc/springcloud-config.git</code></li>
</ul>
<p>此时在工作目录会创建名为springcloud-config的文件夹。</p>
<p>在springcloud-config的文件夹种创建三个配置文件（为本次教学使用的）,随后git add .，git commit -m “sth”等一系列上传操作上传到springcloud-config的新Repository。</p>
<ul>
<li>config-dev.yml</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">config:</span></span><br><span class="line">  <span class="attr">info:</span> <span class="string">&quot;master branch,springcloud-config/config-dev.yml version=7&quot;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>config-prod.yml</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">config:</span></span><br><span class="line">  <span class="attr">info:</span> <span class="string">&quot;master branch,springcloud-config/config-prod.yml version=1&quot;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>config-test.yml</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">config:</span></span><br><span class="line">  <span class="attr">info:</span> <span class="string">&quot;master branch,springcloud-config/config-test.yml version=1&quot;</span> </span><br></pre></td></tr></table></figure>

<p>新建Module模块cloud-config-center-3344，它即为Cloud的配置中心模块CloudConfig Center</p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-bus-amqp<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-config-server<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">3344</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span>  <span class="string">cloud-config-center</span> <span class="comment">#注册进Eureka服务器的微服务名</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">config:</span></span><br><span class="line">      <span class="attr">server:</span></span><br><span class="line">        <span class="attr">git:</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">https://gitee.com/lijunxi666/springcloud-config.git</span> <span class="comment">#GitHub上面的git仓库名字</span></span><br><span class="line">          <span class="comment">####搜索目录</span></span><br><span class="line">          <span class="attr">search-paths:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">springcloud-config</span></span><br><span class="line">          <span class="attr">skip-ssl-validation:</span> <span class="literal">true</span></span><br><span class="line">      <span class="comment">####读取分支</span></span><br><span class="line">      <span class="attr">label:</span> <span class="string">master</span></span><br><span class="line"><span class="comment">#服务注册到eureka地址</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka,http://localhost:7002/eureka</span></span><br></pre></td></tr></table></figure>

<p>主启动类加上<code>@EnableConfigServer</code></p>
<p>windows下修改hosts文件，增加映射</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1 config-3344.com</span><br></pre></td></tr></table></figure>

<p><strong>测试</strong></p>
<p>启动ConfigCenterMain3344</p>
<p>浏览器防问 - <a target="_blank" rel="noopener" href="http://config-3344.com:3344/master/config-dev.yml">http://config-3344.com:3344/master/config-dev.yml</a></p>
<p>页面返回结果：</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">config:</span></span><br><span class="line">  <span class="attr">info:</span> <span class="string">&quot;master branch,springcloud-config/config-dev.yml version=7&quot;</span></span><br></pre></td></tr></table></figure>

<p><strong>访问文件的路径</strong></p>
<p>重要配置细节总结</p>
<ul>
<li>&#x2F;{name}-{profiles}.yml</li>
<li>&#x2F;{label}-{name}-{profiles}.yml</li>
<li>label：分支(branch)</li>
<li>name：服务名</li>
<li>profiles：环境(dev&#x2F;test&#x2F;prod)</li>
</ul>
<p>成功实现了用SpringCloud Config通过GitHub获取配置信息</p>
<h4 id="Config客户端配置与测试"><a href="#Config客户端配置与测试" class="headerlink" title="Config客户端配置与测试"></a>Config客户端配置与测试</h4><p><strong>新建cloud-config-client-3355</strong></p>
<p><strong>POM</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-bus-amqp<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-config-server<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>bootstrap.yml</strong></p>
<p>applicaiton.yml是用户级的资源配置项</p>
<p>bootstrap.yml是系统级的，优先级更加高</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">3355</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">config-client</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="comment">#Config客户端配置</span></span><br><span class="line">    <span class="attr">config:</span></span><br><span class="line">      <span class="attr">label:</span> <span class="string">master</span> <span class="comment">#分支名称</span></span><br><span class="line">      <span class="attr">name:</span> <span class="string">config</span> <span class="comment">#配置文件名称</span></span><br><span class="line">      <span class="attr">profile:</span> <span class="string">dev</span> <span class="comment">#读取后缀名称   上述3个综合：master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml</span></span><br><span class="line">      <span class="attr">uri:</span> <span class="string">http://localhost:3344</span> <span class="comment">#配置中心地址k</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#服务注册到eureka地址</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka</span></span><br></pre></td></tr></table></figure>

<p><strong>主启动</strong>添加<code>@EnableEurekaClient</code></p>
<p><strong>业务类</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RefreshScope</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConfigClientController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;config.info&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String configInfo;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/configInfo&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getConfigInfo</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> configInfo;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>测试</strong></p>
<ul>
<li><p>启动Config配置中心3344微服务并自测</p>
<ul>
<li><a target="_blank" rel="noopener" href="http://config-3344.com:3344/master/config-prod.yml">http://config-3344.com:3344/master/config-prod.yml</a></li>
<li><a target="_blank" rel="noopener" href="http://config-3344.com:3344/master/config-dev.yml">http://config-3344.com:3344/master/config-dev.yml</a></li>
</ul>
</li>
<li><p>启动3355作为Client准备访问</p>
<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:3355/configlnfo">http://localhost:3355/configlnfo</a></li>
</ul>
</li>
</ul>
<p><strong>成功实现了客户端3355访问SpringCloud Config3344通过GitHub获取配置信息可题随时而来</strong></p>
<p><strong>分布式配置的动态刷新问题</strong></p>
<ul>
<li>Linux运维修改GitHub上的配置文件内容做调整</li>
<li>刷新3344，发现ConfigServer配置中心立刻响应</li>
<li>刷新3355，发现ConfigClient客户端没有任何响应</li>
<li>3355没有变化除非自己重启或者重新加载</li>
<li>难到每次运维修改配置文件，客户端都需要重启??噩梦</li>
</ul>
<h3 id="Config动态刷新手动版"><a href="#Config动态刷新手动版" class="headerlink" title="Config动态刷新手动版"></a>Config动态刷新手动版</h3><p>避免每次更新配置都要重启客户端微服务3355</p>
<p><strong>动态刷新步骤</strong>：</p>
<p>修改3355模块</p>
<p>POM引入actuator监控</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>修改YML，添加暴露监控端口配置：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 暴露监控端点</span></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&quot;*&quot;</span></span><br></pre></td></tr></table></figure>

<p>业务类Controller添加<code>@RefreshScope</code></p>
<p><strong>测试</strong></p>
<p>此时修改github配置文件内容 -&gt; 访问3344 -&gt; 访问3355：<a target="_blank" rel="noopener" href="http://localhost:3355/configInfo">http://localhost:3355/configInfo</a></p>
<p>发现3355的内容<strong>并没</strong>刷新</p>
<p><strong>还需要一步</strong></p>
<p>需要运维人员发送Post请求刷新3355</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -X POST &quot;http://localhost:3355/actuator/refresh&quot;</span><br></pre></td></tr></table></figure>

<p>再次测试：<a target="_blank" rel="noopener" href="http://localhost:3355/configInfo">http://localhost:3355/configInfo</a></p>
<p>3355 <strong>改了</strong>。</p>
<p>成功实现了客户端3355刷新到最新配置内容，避免了服务重启</p>
<p><strong>存在的问题</strong></p>
<ul>
<li>假如有多个微服务客户端3355&#x2F;3366&#x2F;3377</li>
<li>每个微服务都要执行—次post请求，手动刷新?</li>
<li>可否广播，一次通知，处处生效?</li>
<li>我们想大范围的自动刷新，求方法</li>
</ul>
<p>这时候就需要用到<strong>消息总线</strong></p>
<h2 id="消息总线"><a href="#消息总线" class="headerlink" title="消息总线"></a>消息总线</h2><p>一言以蔽之，分布式自动刷新配置功能。</p>
<p>Spring Cloud Bus配合Spring Cloud Config使用可以实现配置的动态刷新。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/458fd679c01274ca84f785e1f75c1336.png" alt="d1xased.png"></p>
<p>Spring Cloud Bus能管理和传播分布式系统间的消息，就像一个分布式执行器，可用于广播状态更改、事件推送等，也可以当作微服务间的通信通道。</p>
<p><strong>为何被称为总线</strong></p>
<p>什么是总线？</p>
<p>在微服务架构的系统中，通常会使用轻量级的消息代理来构建一个共用的消息主题，并让系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费，所以称它为消息总线。在总线上的各个实例，都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息。</p>
<p>基本原理</p>
<p>ConfigClient实例都监听MQ中同一个topic(默认是Spring Cloud Bus)。当一个服务刷新数据的时候，它会把这个信息放入到Topic中，这样其它监听同一Topic的服务就能得到通知，然后去更新自身的配置。</p>
<h3 id="RabbitMQ"><a href="#RabbitMQ" class="headerlink" title="RabbitMQ"></a>RabbitMQ</h3><h4 id="环境配置"><a href="#环境配置" class="headerlink" title="环境配置"></a>环境配置</h4><p>严格遵循erlang和rabbitmq版本对应：<a target="_blank" rel="noopener" href="https://www.rabbitmq.com/which-erlang.html">RabbitMQ Erlang Version Requirements — RabbitMQ</a></p>
<ul>
<li><p>安装Erlang，下载地址：<a target="_blank" rel="noopener" href="http://erlang.org/download/otp_win64_21.3.exe">http://erlang.org/download/otp_win64_21.3.exe</a></p>
</li>
<li><p>安装RabbitMQ，下载地址：<a target="_blank" rel="noopener" href="https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.14/rabbitmq-server-3.7.14.exe">https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.14/rabbitmq-server-3.7.14.exe</a></p>
</li>
<li><p>打开cmd进入RabbitMQ安装目录下的sbin目录，如：D:\devSoft\RabbitMQ Scrverk\rabbitmq_server-3.7.14\sbin</p>
</li>
<li><p>输入以下命令启动管理功能<code>rabbitmq-plugins enable rabbitmq _management</code></p>
</li>
</ul>
<p>这样就可以添加可视化插件。</p>
<ul>
<li>访问地址查看是否安装成功：<a target="_blank" rel="noopener" href="http://localhost:15672/">http://localhost:15672/</a></li>
<li>输入账号密码并登录：guest guest</li>
</ul>
<h4 id="Bus动态刷新全局广播的设计思想和选型"><a href="#Bus动态刷新全局广播的设计思想和选型" class="headerlink" title="Bus动态刷新全局广播的设计思想和选型"></a>Bus动态刷新全局广播的设计思想和选型</h4><p>必须先具备良好的RabbitMQ环境先</p>
<p>演示广播效果，增加复杂度，再以3355为模板再制作一个3366</p>
<p>1.新建cloud-config-client-3366</p>
<p>2.POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-bus-amqp<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-config<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>3.YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">3366</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">config-client</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="comment">#Config客户端配置</span></span><br><span class="line">    <span class="attr">config:</span></span><br><span class="line">      <span class="attr">label:</span> <span class="string">master</span> <span class="comment">#分支名称</span></span><br><span class="line">      <span class="attr">name:</span> <span class="string">config</span> <span class="comment">#配置文件名称</span></span><br><span class="line">      <span class="attr">profile:</span> <span class="string">dev</span> <span class="comment">#读取后缀名称   上述3个综合：master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml</span></span><br><span class="line">      <span class="attr">uri:</span> <span class="string">http://localhost:3344</span> <span class="comment">#配置中心地址</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#rabbitmq相关配置 15672是Web管理界面的端口；5672是MQ访问的端口</span></span><br><span class="line">  <span class="attr">rabbitmq:</span></span><br><span class="line">    <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">    <span class="attr">username:</span> <span class="string">guest</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">guest</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#服务注册到eureka地址</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka,</span> <span class="string">http://localhost:7002/eureka</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 暴露监控端点</span></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&quot;*&quot;</span></span><br></pre></td></tr></table></figure>

<p>4.主启动添加<code>@EnableEurekaClient</code></p>
<p>5.controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RefreshScope</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConfigClientController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;server.port&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String serverPort;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;config.info&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String configInfo;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/configInfo&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">configInfo</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;serverPort: &quot;</span>+serverPort+<span class="string">&quot;\t\n\n configInfo: &quot;</span>+configInfo;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>设计思想</strong></p>
<p>1.利用消息总线触发一个客户端&#x2F;bus&#x2F;refresh,而刷新所有客户端的配置</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/3a0975f4bac7393fe406821531e9daef.png" alt="dascx.png"></p>
<p>2.利用消息总线触发一个服务端ConfigServer的&#x2F;bus&#x2F;refresh端点，而刷新所有客户端的配置</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/e2809f728b8eb3e776883e4f905b8712.png" alt="2150vg0.png"></p>
<p>图二的架构显然更加适合，图—不适合的原因如下：</p>
<ul>
<li><p>打破了微服务的职责单一性，因为微服务本身是业务模块，它本不应该承担配置刷新的职责。</p>
</li>
<li><p>破坏了微服务各节点的对等性。</p>
</li>
<li><p>有一定的局限性。例如，微服务在迁移时，它的网络地址常常会发生变化，此时如果想要做到自动刷新，那就会增加更多的修改。</p>
</li>
</ul>
<h4 id="Bus动态刷新全局广播配置实现"><a href="#Bus动态刷新全局广播配置实现" class="headerlink" title="Bus动态刷新全局广播配置实现"></a>Bus动态刷新全局广播配置实现</h4><p><strong>给cloud-config-center-3344配置中心服务端添加消息总线支持</strong></p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--添加消息总线RabbitNQ支持--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-bus-amap<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org-springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">3344</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span>  <span class="string">cloud-config-center</span> <span class="comment">#注册进Eureka服务器的微服务名</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">config:</span></span><br><span class="line">      <span class="attr">server:</span></span><br><span class="line">        <span class="attr">git:</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">git@github.com:zzyybs/springcloud-config.git</span> <span class="comment">#GitHub上面的git仓库名字</span></span><br><span class="line">        <span class="comment">####搜索目录</span></span><br><span class="line">          <span class="attr">search-paths:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">springcloud-config</span></span><br><span class="line">      <span class="comment">####读取分支</span></span><br><span class="line">      <span class="attr">label:</span> <span class="string">master</span></span><br><span class="line"><span class="comment">#rabbitmq相关配置&lt;--------------------------</span></span><br><span class="line"><span class="attr">rabbitmq:</span></span><br><span class="line">    <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">    <span class="attr">username:</span> <span class="string">guest</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">guest</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#服务注册到eureka地址</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka,http://localhost:7002/eureka</span></span><br><span class="line"></span><br><span class="line"><span class="comment">##rabbitmq相关配置,暴露bus刷新配置的端点&lt;--------------------------</span></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span> <span class="comment">#暴露bus刷新配置的端点</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&#x27;bus-refresh&#x27;</span></span><br></pre></td></tr></table></figure>

<p><strong>给cloud-config-client-3355客户端添加消息总线支持</strong></p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--添加消息总线RabbitNQ支持--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-bus-amap<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org-springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">3355</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span>  <span class="string">cloud-config-center</span> <span class="comment">#注册进Eureka服务器的微服务名</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">config:</span></span><br><span class="line">      <span class="attr">server:</span></span><br><span class="line">        <span class="attr">git:</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">git@github.com:zzyybs/springcloud-config.git</span> <span class="comment">#GitHub上面的git仓库名字</span></span><br><span class="line">        <span class="comment">####搜索目录</span></span><br><span class="line">          <span class="attr">search-paths:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">springcloud-config</span></span><br><span class="line">      <span class="comment">####读取分支</span></span><br><span class="line">      <span class="attr">label:</span> <span class="string">master</span></span><br><span class="line"><span class="comment">#rabbitmq相关配置&lt;--------------------------</span></span><br><span class="line"><span class="attr">rabbitmq:</span></span><br><span class="line">    <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">    <span class="attr">username:</span> <span class="string">guest</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">guest</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#服务注册到eureka地址</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka,http://localhost:7002/eureka</span></span><br><span class="line"></span><br><span class="line"><span class="comment">##rabbitmq相关配置,暴露bus刷新配置的端点&lt;--------------------------</span></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span> <span class="comment">#暴露bus刷新配置的端点</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&#x27;bus-refresh&#x27;</span></span><br></pre></td></tr></table></figure>

<p><strong>给cloud-config-client-3366客户端添加消息总线支持</strong></p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--添加消息总线RabbitNQ支持--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-bus-amap<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org-springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">3366</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">config-client</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="comment">#Config客户端配置</span></span><br><span class="line">    <span class="attr">config:</span></span><br><span class="line">      <span class="attr">label:</span> <span class="string">master</span> <span class="comment">#分支名称</span></span><br><span class="line">      <span class="attr">name:</span> <span class="string">config</span> <span class="comment">#配置文件名称</span></span><br><span class="line">      <span class="attr">profile:</span> <span class="string">dev</span> <span class="comment">#读取后缀名称   上述3个综合：master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml</span></span><br><span class="line">      <span class="attr">uri:</span> <span class="string">http://localhost:3344</span> <span class="comment">#配置中心地址</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#rabbitmq相关配置 15672是Web管理界面的端口；5672是MQ访问的端口&lt;-----------------------</span></span><br><span class="line">  <span class="attr">rabbitmq:</span></span><br><span class="line">    <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">    <span class="attr">username:</span> <span class="string">guest</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">guest</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#服务注册到eureka地址</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka,http://localhost:7002/eureka</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 暴露监控端点</span></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&quot;*&quot;</span></span><br></pre></td></tr></table></figure>

<p><strong>测试</strong></p>
<ul>
<li><p>启动</p>
<ul>
<li>EurekaMain7001</li>
<li>EurekaMain7002</li>
<li>ConfigcenterMain3344</li>
<li>ConfigclientMain3355</li>
<li>ConfigclicntMain3366</li>
</ul>
</li>
<li><p>运维工程师</p>
<ul>
<li>修改Github上配置文件内容，增加版本号</li>
<li>发送POST请求<ul>
<li><code>curl -X POST &quot;http://localhost:3344/actuator/bus-refresh&quot;</code></li>
<li><strong>—次发送，处处生效</strong></li>
</ul>
</li>
</ul>
</li>
<li><p>配置中心</p>
<ul>
<li><a target="_blank" rel="noopener" href="http://config-3344.com:3344/config-dev.yml">http://config-3344.com:3344/config-dev.yml</a></li>
</ul>
</li>
<li><p>客户端</p>
<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:3355/configlnfo">http://localhost:3355/configlnfo</a></li>
<li><a target="_blank" rel="noopener" href="http://localhost:3366/configInfo">http://localhost:3366/configInfo</a></li>
<li>获取配置信息，发现都已经刷新了</li>
</ul>
</li>
</ul>
<p><strong>—次修改，广播通知，处处生效</strong></p>
<h4 id="Bus动态刷新定点通知"><a href="#Bus动态刷新定点通知" class="headerlink" title="Bus动态刷新定点通知"></a>Bus动态刷新定点通知</h4><p>不想全部通知，只想定点通知</p>
<ul>
<li>只通知3355</li>
<li>不通知3366</li>
</ul>
<p>简单一句话 - <strong>指定具体某一个实例生效而不是全部</strong></p>
<ul>
<li>公式：<a target="_blank" rel="noopener" href="http://localhost:3344/actuator/bus-refresh/%7Bdestination%7D">http://localhost:3344/actuator/bus-refresh/{destination}</a></li>
<li>&#x2F;bus&#x2F;refresh请求不再发送到具体的服务实例上，而是发给config server通过destination参数类指定需要更新配置的服务或实例</li>
</ul>
<p>案例</p>
<ul>
<li>我们这里以刷新运行在3355端口上的config-client（配置文件中设定的应用名称）为例，只通知3355，不通知3366</li>
<li><code>curl -X POST &quot;http://localhost:3344/actuator/bus-refresh/config-client:3355</code></li>
</ul>
<p><strong>消息通知总结</strong></p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/ccd5fcc8293edec24d7e889e189d0bfe.png" alt="21cx0943.png"></p>
<h2 id="消息驱动"><a href="#消息驱动" class="headerlink" title="消息驱动"></a>消息驱动</h2><h3 id="Stream"><a href="#Stream" class="headerlink" title="Stream"></a>Stream</h3><p><strong>什么是Spring Cloud Stream？</strong></p>
<p>官方定义Spring Cloud Stream是一个构建消息驱动微服务的框架。</p>
<p>应用程序通过inputs或者 outputs 来与Spring Cloud Stream中binder对象交互。</p>
<p>通过我们配置来binding(绑定)，而Spring Cloud Stream 的binder对象负责与消息中间件交互。所以，我们只需要搞清楚如何与Spring Cloud Stream交互就可以方便使用消息驱动的方式。</p>
<p>通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动。<br>Spring Cloud Stream为一些供应商的消息中间件产品提供了个性化的自动化配置实现，引用了发布-订阅、消费组、分区的三个核心概念。</p>
<p>目前仅支持RabbitMQ、 Kafka。</p>
<h4 id="设计思想"><a href="#设计思想" class="headerlink" title="设计思想"></a>设计思想</h4><p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/1ca02dd31581d92a7a610bcd137f6848.png" alt="dasd04.png"></p>
<ul>
<li>生产者&#x2F;消费者之间靠消息媒介传递信息内容</li>
<li>消息必须走特定的通道 - 消息通道 Message Channel</li>
<li>消息通道里的消息如何被消费呢，谁负责收发处理 - 消息通道MessageChannel的子接口SubscribableChannel，由</li>
<li>MessageHandler消息处理器所订阅。</li>
</ul>
<h4 id="常用注解"><a href="#常用注解" class="headerlink" title="常用注解"></a>常用注解</h4><table>
<thead>
<tr>
<th align="center"><strong>组成</strong></th>
<th align="center"><strong>说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td align="center">Middleware</td>
<td align="center">中间件，目前只支持RabbitMQ和Kafka</td>
</tr>
<tr>
<td align="center">Binder</td>
<td align="center">inder是应用与消息中间件之间的封装，目前实行了Kafka和RabbitMQ的Binder，通过Binder可以很方便的连接中间件，可以动态的改变消息类型(对应于Kafka的topic,RabbitMQ的exchange)，这些都可以通过配置文件来实现</td>
</tr>
<tr>
<td align="center">@Input</td>
<td align="center">注解标识输入通道，通过该输乎通道接收到的消息进入应用程序</td>
</tr>
<tr>
<td align="center">@Output</td>
<td align="center">注解标识输出通道，发布的消息将通过该通道离开应用程序</td>
</tr>
<tr>
<td align="center">@StreamListener</td>
<td align="center">监听队列，用于消费者的队列的消息接收</td>
</tr>
<tr>
<td align="center">@EnableBinding</td>
<td align="center">指信道channel和exchange绑定在一起</td>
</tr>
</tbody></table>
<p> <strong>案例说明</strong></p>
<p>准备RabbitMQ环境</p>
<p>工程中新建三个子模块</p>
<ul>
<li>cloud-stream-rabbitmq-provider8801，作为生产者进行发消息模块</li>
<li>cloud-stream-rabbitmq-consumer8802，作为消息接收模块</li>
<li>cloud-stream-rabbitmq-consumer8803，作为消息接收模块</li>
</ul>
<h4 id="Stream消息驱动之生产者"><a href="#Stream消息驱动之生产者" class="headerlink" title="Stream消息驱动之生产者"></a>Stream消息驱动之生产者</h4><p>新建Module：cloud-stream-rabbitmq-provider8801</p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-stream-rabbit<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8801</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloud-stream-provider</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">      <span class="attr">stream:</span></span><br><span class="line">        <span class="attr">binders:</span> <span class="comment"># 在此处配置要绑定的rabbitmq的服务信息；</span></span><br><span class="line">          <span class="attr">defaultRabbit:</span> <span class="comment"># 表示定义的名称，用于于binding整合</span></span><br><span class="line">            <span class="attr">type:</span> <span class="string">rabbit</span> <span class="comment"># 消息组件类型</span></span><br><span class="line">            <span class="attr">environment:</span> <span class="comment"># 设置rabbitmq的相关的环境配置</span></span><br><span class="line">              <span class="attr">spring:</span></span><br><span class="line">                <span class="attr">rabbitmq:</span></span><br><span class="line">                  <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">                  <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">                  <span class="attr">username:</span> <span class="string">guest</span></span><br><span class="line">                  <span class="attr">password:</span> <span class="string">guest</span></span><br><span class="line">        <span class="attr">bindings:</span> <span class="comment"># 服务的整合处理</span></span><br><span class="line">          <span class="attr">output:</span> <span class="comment"># 这个名字是一个通道的名称</span></span><br><span class="line">            <span class="attr">destination:</span> <span class="string">studyExchange</span> <span class="comment"># 表示要使用的Exchange名称定义</span></span><br><span class="line">            <span class="attr">content-type:</span> <span class="string">application/json</span> <span class="comment"># 设置消息类型，本次为json，文本则设置“text/plain”</span></span><br><span class="line">            <span class="attr">binder:</span> <span class="string">defaultRabbit</span> <span class="comment"># 设置要绑定的消息服务的具体设置</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span> <span class="comment"># 客户端进行Eureka注册的配置</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">lease-renewal-interval-in-seconds:</span> <span class="number">2</span> <span class="comment"># 设置心跳的时间间隔（默认是30秒）</span></span><br><span class="line">    <span class="attr">lease-expiration-duration-in-seconds:</span> <span class="number">5</span> <span class="comment"># 如果现在超过了5秒的间隔（默认是90秒）</span></span><br><span class="line">    <span class="attr">instance-id:</span> <span class="string">send-8801.com</span>  <span class="comment"># 在信息列表时显示主机名称</span></span><br><span class="line">    <span class="attr">prefer-ip-address:</span> <span class="literal">true</span>     <span class="comment"># 访问的路径变为IP地址</span></span><br></pre></td></tr></table></figure>

<p>主启动类StreamMQMain8801</p>
<p>业务类</p>
<p>1.发送消息接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">IMessageProvider</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">send</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>2.发送消息接口实现类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableBinding(Source.class)</span> <span class="comment">//定义消息的推送管道</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MessageProviderImpl</span> <span class="keyword">implements</span> <span class="title class_">IMessageProvider</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> MessageChannel output; <span class="comment">// 消息发送管道</span></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">send</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">serial</span> <span class="operator">=</span> UUID.randomUUID().toString();</span><br><span class="line">        output.send(MessageBuilder.withPayload(serial).build());</span><br><span class="line">        System.out.println(<span class="string">&quot;*****serial: &quot;</span>+serial);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>3.Controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SendMessageController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> IMessageProvider messageProvider;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(value = &quot;/sendMessage&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">sendMessage</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> messageProvider.send();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试</p>
<ul>
<li><p>启动 7001eureka</p>
</li>
<li><p>启动 RabpitMq（</p>
<p>79_Bus之RabbitMQ环境配置</p>
<p>）</p>
<ul>
<li>rabbitmq-plugins enable rabbitmq_management</li>
<li><a target="_blank" rel="noopener" href="http://localhost:15672/">http://localhost:15672/</a></li>
</ul>
</li>
<li><p>启动 8801</p>
</li>
<li><p>访问 - <a target="_blank" rel="noopener" href="http://localhost:8801/sendMessage">http://localhost:8801/sendMessage</a></p>
<ul>
<li>后台将打印<code>serial: UUID</code>字符串</li>
</ul>
</li>
</ul>
<h4 id="Stream消息驱动之消费者"><a href="#Stream消息驱动之消费者" class="headerlink" title="Stream消息驱动之消费者"></a>Stream消息驱动之消费者</h4><p>新建Module：cloud-stream-rabbitmq-consumer8802</p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-stream-rabbit<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8802</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloud-stream-consumer</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">      <span class="attr">stream:</span></span><br><span class="line">        <span class="attr">binders:</span> <span class="comment"># 在此处配置要绑定的rabbitmq的服务信息；</span></span><br><span class="line">          <span class="attr">defaultRabbit:</span> <span class="comment"># 表示定义的名称，用于于binding整合</span></span><br><span class="line">            <span class="attr">type:</span> <span class="string">rabbit</span> <span class="comment"># 消息组件类型</span></span><br><span class="line">            <span class="attr">environment:</span> <span class="comment"># 设置rabbitmq的相关的环境配置</span></span><br><span class="line">              <span class="attr">spring:</span></span><br><span class="line">                <span class="attr">rabbitmq:</span></span><br><span class="line">                  <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">                  <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">                  <span class="attr">username:</span> <span class="string">guest</span></span><br><span class="line">                  <span class="attr">password:</span> <span class="string">guest</span></span><br><span class="line">        <span class="attr">bindings:</span> <span class="comment"># 服务的整合处理</span></span><br><span class="line">          <span class="attr">input:</span> <span class="comment"># 这个名字是一个通道的名称</span></span><br><span class="line">            <span class="attr">destination:</span> <span class="string">studyExchange</span> <span class="comment"># 表示要使用的Exchange名称定义</span></span><br><span class="line">            <span class="attr">content-type:</span> <span class="string">application/json</span> <span class="comment"># 设置消息类型，本次为对象json，如果是文本则设置“text/plain”</span></span><br><span class="line">            <span class="attr">binder:</span> <span class="string">defaultRabbit</span> <span class="comment"># 设置要绑定的消息服务的具体设置</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span> <span class="comment"># 客户端进行Eureka注册的配置</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka,</span> <span class="string">http://localhost:7002/eureka</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">lease-renewal-interval-in-seconds:</span> <span class="number">2</span> <span class="comment"># 设置心跳的时间间隔（默认是30秒）</span></span><br><span class="line">    <span class="attr">lease-expiration-duration-in-seconds:</span> <span class="number">5</span> <span class="comment"># 如果现在超过了5秒的间隔（默认是90秒）</span></span><br><span class="line">    <span class="attr">instance-id:</span> <span class="string">receive-8802.com</span>  <span class="comment"># 在信息列表时显示主机名称</span></span><br><span class="line">    <span class="attr">prefer-ip-address:</span> <span class="literal">true</span>     <span class="comment"># 访问的路径变为IP地址</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h4 id="Stream之消息重复消费"><a href="#Stream之消息重复消费" class="headerlink" title="Stream之消息重复消费"></a>Stream之消息重复消费</h4><p>依照8802，克隆出来一份运行8803 - cloud-stream-rabbitmq-consumer8803。</p>
<p>原神，<strong>启动</strong></p>
<ul>
<li>RabbitMQ</li>
<li>服务注册 - 8801</li>
<li>消息生产 - 8801</li>
<li>消息消费 - 8802</li>
<li>消息消费 - 8802</li>
</ul>
<p><strong>运行后有两个问题</strong></p>
<ol>
<li>有重复消费问题</li>
<li>消息持久化问题</li>
</ol>
<p><strong>消费</strong></p>
<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:8801/sendMessage">http://localhost:8801/sendMessage</a></li>
<li>目前是8802&#x2F;8803同时都收到了，存在重复消费问题</li>
<li>如何解决：分组和持久化属性group（重要）</li>
</ul>
<p><strong>生产实际案例</strong></p>
<p>比如在如下场景中，订单系统我们做集群部署，都会从RabbitMQ中获取订单信息，那如果一个订单同时被两个服务获取到，那么就会造成数据错误，我们得避免这种情况。这时我们就可以<strong>使用Stream中的消息分组来解决</strong>。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/f61e83441af907a42e8886368bde59ff.png" alt="d123654.png"></p>
<p>注意在Stream中处于同一个group中的多个消费者是竞争关系，就能够保证消息只会被其中一个应用消费一次。不同组是可以全面消费的(重复消费)。</p>
<p>简单总结：只需要每个服务处于统一group下就不会出现重复消费</p>
<p><strong>解决</strong></p>
<p>原理</p>
<p>微服务应用放置于同一个group中，就能够保证消息只会被其中一个应用消费一次。</p>
<p>不同的组是可以重复消费的，同一个组内会发生竞争关系，只有其中一个可以消费。</p>
<p>8802&#x2F;8803都变成不同组，group两个不同</p>
<p>group: A_Group、B_Group</p>
<p>8802修改YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloud-stream-provider</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">      <span class="attr">stream:</span></span><br><span class="line">        <span class="attr">binders:</span> <span class="comment"># 在此处配置要绑定的rabbitmq的服务信息；</span></span><br><span class="line">          <span class="attr">defaultRabbit:</span> <span class="comment"># 表示定义的名称，用于于binding整合</span></span><br><span class="line">            <span class="attr">type:</span> <span class="string">rabbit</span> <span class="comment"># 消息组件类型</span></span><br><span class="line">            <span class="attr">environment:</span> <span class="comment"># 设置rabbitmq的相关的环境配置</span></span><br><span class="line">              <span class="attr">spring:</span></span><br><span class="line">                <span class="attr">rabbitmq:</span></span><br><span class="line">                  <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">                  <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">                  <span class="attr">username:</span> <span class="string">guest</span></span><br><span class="line">                  <span class="attr">password:</span> <span class="string">guest</span></span><br><span class="line">        <span class="attr">bindings:</span> <span class="comment"># 服务的整合处理</span></span><br><span class="line">          <span class="attr">output:</span> <span class="comment"># 这个名字是一个通道的名称</span></span><br><span class="line">            <span class="attr">destination:</span> <span class="string">studyExchange</span> <span class="comment"># 表示要使用的Exchange名称定义</span></span><br><span class="line">            <span class="attr">content-type:</span> <span class="string">application/json</span> <span class="comment"># 设置消息类型，本次为json，文本则设置“text/plain”</span></span><br><span class="line">            <span class="attr">binder:</span> <span class="string">defaultRabbit</span> <span class="comment"># 设置要绑定的消息服务的具体设置</span></span><br><span class="line">            <span class="attr">group:</span> <span class="string">A_Group</span> <span class="comment">#&lt;----------------------------------------关键</span></span><br></pre></td></tr></table></figure>

<p>8803修改YML（与8802的类似位置 <code>group: B_Group</code>）</p>
<p>结论：<strong>还是重复消费</strong></p>
<p>8802&#x2F;8803实现了轮询分组，每次只有一个消费者，8801模块的发的消息只能被8802或8803其中一个接收到，这样避免了重复消费。</p>
<p><strong>8802&#x2F;8803都变成相同组，group两个相同</strong></p>
<p>group: A_Group</p>
<p>8802修改YML<code>group: A_Group</code></p>
<p>8803修改YML<code>group: A_Group</code></p>
<p>结论：同一个组的多个微服务实例，每次只会有一个拿到</p>
<p>成功解决重复消费</p>
<h4 id="Stream之消息持久化"><a href="#Stream之消息持久化" class="headerlink" title="Stream之消息持久化"></a>Stream之消息持久化</h4><p>通过上述，解决了重复消费问题，再看看持久化。</p>
<p>停止8802&#x2F;8803并去除掉8802的分组group: A_Group，8803的分组group: A_Group没有去掉。</p>
<p>8801先发送4条消息到RabbitMq。</p>
<p>先启动8802，<strong>无分组属性配置</strong>，后台没有打出来消息。</p>
<p>再启动8803，<strong>有分组属性配置</strong>，后台打出来了MQ上的消息。(消息持久化体现)</p>
<h2 id="分布式请求链路跟踪"><a href="#分布式请求链路跟踪" class="headerlink" title="分布式请求链路跟踪"></a>分布式请求链路跟踪</h2><h3 id="Sleuth"><a href="#Sleuth" class="headerlink" title="Sleuth"></a>Sleuth</h3><p><strong>为什么会出现这个技术？要解决哪些问题？</strong></p>
<p>在微服务框架中，一个由客户端发起的请求在后端系统中会经过多个不同的的服务节点调用来协同产生最后的请求结果，每一个前段请求都会形成一条复杂的分布式服务调用链路，链路中的任何一环出现高延时或错误都会引起整个请求最后的失败。</p>
<p><strong>是什么</strong></p>
<ul>
<li><a target="_blank" rel="noopener" href="https://github.com/spring-cloud/spring-cloud-sleuth">https://github.com/spring-cloud/spring-cloud-sleuth</a></li>
<li>Spring Cloud Sleuth提供了一套完整的服务跟踪的解决方案</li>
<li>在分布式系统中提供追踪解决方案并且兼容支持了zipkin</li>
</ul>
<h4 id="Sleuth之zipkin搭建安装"><a href="#Sleuth之zipkin搭建安装" class="headerlink" title="Sleuth之zipkin搭建安装"></a>Sleuth之zipkin搭建安装</h4><p>1.zipkin</p>
<p><strong>下载</strong></p>
<ul>
<li>SpringCloud从F版起已不需要自己构建Zipkin Server了，只需调用jar包即可</li>
<li><a target="_blank" rel="noopener" href="https://repo1.maven.org/maven2/io/zipkin/zipkin-server/">Central Repository: io&#x2F;zipkin&#x2F;zipkin-server (maven.org)</a></li>
<li>zipkin-server-2.24.3-exec.jar</li>
</ul>
<p><strong>运行jar</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar zipkin-server-<span class="number">2.24</span><span class="number">.3</span>-exec.jar</span><br></pre></td></tr></table></figure>

<p><strong>运行控制台</strong></p>
<p><a target="_blank" rel="noopener" href="http://localhost:9411/zipkin/">http://localhost:9411/zipkin/</a></p>
<p><strong>完整的调用链路</strong></p>
<p>—条链路通过Trace ld唯一标识，Span标识发起的请求信息，各span通过parent id关联起来。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/f75fcfd2146df03428b9c8c53d13c1f1.png" alt="1d9012.png"></p>
<p>名词解释</p>
<ul>
<li>Trace：类似于树结构的Span集合，表示一条调用链路，存在唯一标识</li>
<li>span：表示调用链路来源，通俗的理解span就是一次请求信息</li>
</ul>
<h4 id="Sleuth链路监控展现"><a href="#Sleuth链路监控展现" class="headerlink" title="Sleuth链路监控展现"></a>Sleuth链路监控展现</h4><p><strong>修改cloud-provider-payment8001</strong></p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--包含了sleuth+zipkin--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-zipkin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloud-payment-service</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">zipkin:</span> <span class="comment">#&lt;-------------------------------------关键 </span></span><br><span class="line">      <span class="attr">base-url:</span> <span class="string">http://localhost:9411</span></span><br><span class="line">  <span class="attr">sleuth:</span> <span class="comment">#&lt;-------------------------------------关键</span></span><br><span class="line">    <span class="attr">sampler:</span></span><br><span class="line">    <span class="comment">#采样率值介于 0 到 1 之间，1 则表示全部采集</span></span><br><span class="line">    <span class="attr">probability:</span> <span class="number">1</span></span><br></pre></td></tr></table></figure>

<p>业务类PaymentController</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/payment/zipkin&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">paymentZipkin</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;hi ,i&#x27;am paymentzipkin server fall back，welcome to here, O(∩_∩)O哈哈~&quot;</span>;</span><br><span class="line">&#125;    </span><br></pre></td></tr></table></figure>

<p><strong>修改cloue-consumer-order80</strong></p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-zipkin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">spring:</span><br><span class="line">    application:</span><br><span class="line">        name: cloud-order-service</span><br><span class="line">    zipkin:</span><br><span class="line">      base-url: http://localhost:9411</span><br><span class="line">    sleuth:</span><br><span class="line">      sampler:</span><br><span class="line">        probability: 1</span><br></pre></td></tr></table></figure>

<p>业务类OrderController</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/consumer/payment/zipkin&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">paymentZipkin</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> restTemplate.getForObject(<span class="string">&quot;http://localhost:8001&quot;</span>+<span class="string">&quot;/payment/zipkin/&quot;</span>, String.class);</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>4.依次启动eureka7001&#x2F;8001&#x2F;80 - 80调用8001几次测试下</p>
<p>5.打开浏览器访问: <a target="_blank" rel="noopener" href="http://localhost:9411/">http://localhost:9411</a></p>
<h2 id="Spring-Cloud-Alibaba"><a href="#Spring-Cloud-Alibaba" class="headerlink" title="Spring Cloud Alibaba"></a>Spring Cloud Alibaba</h2><p><strong>为什么会出现SpringCloud alibaba?</strong></p>
<p>Spring Cloud Netflix项目进入维护模式</p>
<p><a target="_blank" rel="noopener" href="https://spring.io/blog/2018/12/12/spring-cloud-greenwich-rc1-available-now">https://spring.io/blog/2018/12/12/spring-cloud-greenwich-rc1-available-now</a></p>
<p><strong>什么是维护模式？</strong></p>
<p>将模块置于维护模式，意味着Spring Cloud团队将不会再向模块添加新功能。</p>
<p>他们将修复block级别的 bug 以及安全问题，他们也会考虑并审查社区的小型pull request。</p>
<p><strong>SpringCloud alibaba带来了什么</strong></p>
<p><a target="_blank" rel="noopener" href="https://github.com/alibaba/spring-cloud-alibaba/blob/2.2.x/README-zh.md">spring-cloud-alibaba&#x2F;README-zh.md at 2.2.x · alibaba&#x2F;spring-cloud-alibaba (github.com)</a></p>
<p>Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件，方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。</p>
<p>依托 Spring Cloud Alibaba，您只需要添加一些注解和少量配置，就可以将 Spring Cloud 应用接入阿里微服务解决方案，通过阿里中间件来迅速搭建分布式应用系统。</p>
<p><strong>能干嘛</strong></p>
<ul>
<li>服务限流降级：默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ </li>
<li>限流降级功能的接入，可以在运行时通过控制台实时修改限流降级规则，还支持查看限流降级 Metrics 监控。</li>
<li>服务注册与发现：适配 Spring Cloud 服务注册与发现标准，默认集成了 Ribbon 的支持。</li>
<li>分布式配置管理：支持分布式系统中的外部化配置，配置更改时自动刷新。</li>
<li>消息驱动能力：基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。</li>
<li>分布式事务：使用 @GlobalTransactional 注解， 高效并且对业务零侵入地解决分布式事务问题。</li>
<li>阿里云对象存储：阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。</li>
<li>分布式任务调度：提供秒级、精准、高可靠、高可用的定时（基于 Cron 表达式）任务调度服务。同时提供分布式的任务执行模型，如网格任务。网格任务支持海量子任务均匀分配到所有 Worker（schedulerx-client）上执行。</li>
<li>阿里云短信服务：覆盖全球的短信服务，友好、高效、智能的互联化通讯能力，帮助企业迅速搭建客户触达通道。</li>
</ul>
<p><strong>MAVEN</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-alibaba-dependencies<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.2.5.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>Sentinel：把流量作为切入点，从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。</li>
<li>Nacos：一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。</li>
<li>RocketMQ：一款开源的分布式消息系统，基于高可用分布式集群技术，提供低延时的、高可靠的消息发布与订阅服务。</li>
<li>Dubbo：Apache Dubbo™ 是一款高性能 Java RPC 框架。</li>
<li>Seata：阿里巴巴开源产品，一个易于使用的高性能微服务分布式事务解决方案。</li>
<li>Alibaba Cloud OSS: 阿里云对象存储服务（Object Storage Service，简称 OSS），是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。</li>
<li>Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品，提供秒级、精准、高可靠、高可用的定时（基于 Cron 表达式）任务调度服务。</li>
<li>Alibaba Cloud SMS: 覆盖全球的短信服务，友好、高效、智能的互联化通讯能力，帮助企业迅速搭建客户触达通道。</li>
</ul>
<p><strong>Spring Cloud Alibaba学习资料获取</strong></p>
<ul>
<li>官网</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://spring.io/projects/spring-cloud-alibaba#overview">https://spring.io/projects/spring-cloud-alibaba#overview</a></p>
<ul>
<li>英文</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://github.com/alibaba/spring-cloud-alibaba">https://github.com/alibaba/spring-cloud-alibaba</a><br><a target="_blank" rel="noopener" href="https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html">https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html</a></p>
<ul>
<li>中文</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md">https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md</a></p>
<h3 id="Nacos"><a href="#Nacos" class="headerlink" title="Nacos"></a>Nacos</h3><h4 id="Nacos介绍"><a href="#Nacos介绍" class="headerlink" title="Nacos介绍"></a>Nacos介绍</h4><p><strong>是什么</strong></p>
<ul>
<li>一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。</li>
<li>Nacos: Dynamic Naming and Configuration Service</li>
<li>Nacos就是注册中心＋配置中心的组合 -&gt; <strong>Nacos &#x3D; Eureka+Config+Bus</strong></li>
</ul>
<p><strong>能干嘛</strong></p>
<ul>
<li>替代Eureka做服务注册中心</li>
<li>替代Config做服务配置中心</li>
</ul>
<p><strong>去哪下</strong></p>
<ul>
<li><a target="_blank" rel="noopener" href="https://github.com/alibaba/nacos/releases">https://github.com/alibaba/nacos/releases</a></li>
<li>[官网文档](<a target="_blank" rel="noopener" href="https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring">https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring</a> cloud alibaba nacos_discovery)</li>
</ul>
<p><strong>各中注册中心比较</strong></p>
<table>
<thead>
<tr>
<th>服务注册与发现框架</th>
<th>CAP模型</th>
<th>控制台管理</th>
<th>社区活跃度</th>
</tr>
</thead>
<tbody><tr>
<td>Eureka</td>
<td>AP</td>
<td>支持</td>
<td>低(2.x版本闭源)</td>
</tr>
<tr>
<td>Zookeeper</td>
<td>CP</td>
<td>不支持</td>
<td>中</td>
</tr>
<tr>
<td>consul</td>
<td>CP</td>
<td>支持</td>
<td>高</td>
</tr>
<tr>
<td>Nacos</td>
<td>AP</td>
<td>支持</td>
<td>高</td>
</tr>
</tbody></table>
<p>据说Nacos在阿里巴巴内部有超过10万的实例运行，已经过了类似双十一等各种大型流量的考验。</p>
<h4 id="Nacos安装"><a href="#Nacos安装" class="headerlink" title="Nacos安装"></a>Nacos安装</h4><ul>
<li>本地Java8+Maven环境已经OK先</li>
<li>从<a target="_blank" rel="noopener" href="https://github.com/alibaba/nacos/releases">官网</a>下载Nacos</li>
<li>解压安装包，直接运行bin目录下的startup.cmd</li>
<li>命令运行成功后直接访问<a target="_blank" rel="noopener" href="http://localhost:8848/nacos%EF%BC%8C%E9%BB%98%E8%AE%A4%E8%B4%A6%E5%8F%B7%E5%AF%86%E7%A0%81%E9%83%BD%E6%98%AFnacos">http://localhost:8848/nacos，默认账号密码都是nacos</a></li>
<li>结果页面</li>
</ul>
<h4 id="Nacos之服务提供者注册"><a href="#Nacos之服务提供者注册" class="headerlink" title="Nacos之服务提供者注册"></a>Nacos之服务提供者注册</h4><p><a target="_blank" rel="noopener" href="https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_nacos_discovery">官方文档</a></p>
<p>新建Module - cloudalibaba-provider-payment9001</p>
<p><strong>POM</strong></p>
<p>父POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--spring cloud alibaba 2.1.0.RELEASE--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-alibaba-dependencies<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.1.0.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>本模块POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>YML</strong></p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">9001</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">nacos-payment-provider</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">nacos:</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span> <span class="comment">#配置Nacos地址</span></span><br><span class="line"></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&#x27;*&#x27;</span></span><br></pre></td></tr></table></figure>

<p>主启动添加<code>@EnableDiscoveryClient</code></p>
<p>业务类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentController</span> &#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;server.port&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String serverPort;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(value = &quot;/payment/nacos/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getPayment</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Integer id)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;nacos registry, serverPort: &quot;</span>+ serverPort+<span class="string">&quot;\t id&quot;</span>+id;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试</p>
<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:9001/payment/nacos/1">http://localhost:9001/payment/nacos/1</a></li>
<li>nacos控制台</li>
<li>nacos服务注册中心+服务提供者9001都OK了</li>
</ul>
<p>再建一个新模块<code>cloudalibaba-provider-payment9002</code></p>
<h4 id="Nacos之服务消费者注册和负载"><a href="#Nacos之服务消费者注册和负载" class="headerlink" title="Nacos之服务消费者注册和负载"></a>Nacos之服务消费者注册和负载</h4><p>新建Module - cloudalibaba-consumer-nacos-order83</p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>为什么nacos支持负载均衡？因为spring-cloud-starter-alibaba-nacos-discovery内含netflix-ribbon包。</p>
<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">83</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">nacos-order-consumer</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">nacos:</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)</span></span><br><span class="line"><span class="attr">service-url:</span></span><br><span class="line">  <span class="attr">nacos-user-service:</span> <span class="string">http://nacos-payment-provider</span></span><br></pre></td></tr></table></figure>

<p>主启动添加<code>@EnableDiscoveryClient </code></p>
<p>业务类</p>
<p>ApplicationContextConfig</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ApplicationContextConfig</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@LoadBalanced</span></span><br><span class="line">    <span class="keyword">public</span> RestTemplate <span class="title function_">getRestTemplate</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>OrderNacosController</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderNacosController</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;service-url.nacos-user-service&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String serverURL;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(value = &quot;/consumer/payment/nacos/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">paymentInfo</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Long id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> restTemplate.getForObject(serverURL+<span class="string">&quot;/payment/nacos/&quot;</span>+id,String.class);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试</p>
<ul>
<li>启动nacos控制台</li>
<li><a target="_blank" rel="noopener" href="http://localhost:83/Eonsumer/payment/nacos/13">http://localhost:83/Eonsumer/payment/nacos/13</a><ul>
<li>83访问9001&#x2F;9002，轮询负载OK</li>
</ul>
</li>
</ul>
<h4 id="Nacos之服务配置中心"><a href="#Nacos之服务配置中心" class="headerlink" title="Nacos之服务配置中心"></a>Nacos之服务配置中心</h4><p>基础配置</p>
<p>cloudalibaba-config-nacos-client3377</p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--nacos-config--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-nacos-config<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--nacos-discovery--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<p>Nacos同springcloud-config一样，在项目初始化时，要保证先从配置中心进行配置拉取，拉取配置之后，才能保证项目的正常启动。</p>
<p>springboot中配置文件的加载是存在优先级顺序的，bootstrap优先级高于application</p>
<p>bootstrap</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># nacos配置</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">3377</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">nacos-config-client</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">nacos:</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span> <span class="comment">#Nacos服务注册中心地址</span></span><br><span class="line">      <span class="attr">config:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span> <span class="comment">#Nacos作为配置中心地址</span></span><br><span class="line">        <span class="attr">file-extension:</span> <span class="string">yaml</span> <span class="comment">#指定yaml格式的配置</span></span><br><span class="line">        </span><br><span class="line"><span class="comment"># $&#123;spring.application.name&#125;-$&#123;spring.profile.active&#125;.$&#123;spring.cloud.nacos.config.file-extension&#125;</span></span><br><span class="line"><span class="comment"># nacos-config-client-dev.yaml</span></span><br><span class="line"><span class="comment"># nacos-config-client-test.yaml   ----&gt; config.info</span></span><br></pre></td></tr></table></figure>

<p>application</p>
<figure class="highlight qml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">spring</span>:</span><br><span class="line">  <span class="attribute">profiles</span>:</span><br><span class="line">    <span class="attribute">active</span>: dev # 表示开发环境</span><br><span class="line">    #<span class="attribute">active</span>: test # 表示测试环境</span><br><span class="line">    #<span class="attribute">active</span>: info</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>主启动添加<code>@EnableDiscoveryClient</code></p>
<p>业务类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RefreshScope</span> <span class="comment">//支持Nacos的动态刷新功能。</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConfigClientController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;config.info&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String configInfo;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/config/info&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getConfigInfo</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> configInfo;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>在Nacos中添加配置信息</strong></p>
<p>Nacos中的dataid的组成格式及与SpringBoot配置文件中的匹配规则</p>
<p><a target="_blank" rel="noopener" href="https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html">官方文档</a></p>
<p>说明：之所以需要配置spring.application.name，是因为它是构成Nacos配置管理dataId 字段的一部分。</p>
<p>在 Nacos Spring Cloud中,dataId的完整格式如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$&#123;prefix&#125;-$&#123;spring-profile.active&#125;.$&#123;file-extension&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>prefix默认为spring.application.name的值，也可以通过配置项spring.cloud.nacos.config.prefix来配置。</li>
<li>spring.profile.active即为当前环境对应的 profile，详情可以参考 Spring Boot文档。注意：当spring.profile.active为空时，对应的连接符 - 也将不存在，datald 的拼接格式变成${prefix}.${file-extension}</li>
<li>file-exetension为配置内容的数据格式，可以通过配置项spring .cloud.nacos.config.file-extension来配置。目前只支持properties和yaml类型。</li>
<li>通过Spring Cloud 原生注解@RefreshScope实现配置自动更新。</li>
</ul>
<p>最后公式：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$&#123;spring.application.name)&#125;-$&#123;spring.profiles.active&#125;.$&#123;spring.cloud.nacos.config.file-extension&#125;</span><br></pre></td></tr></table></figure>

<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/05d45948bf637614dbd70e2bc8ce992d.png" alt="21dxw20.png"></p>
<p>Nacos界面配置对应 - 设置DataId</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/c61619bbe5ea16f34efca8103b0f90ba.png" alt="c0tnVf.png"></p>
<p>配置小结</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/b3bffc4a646b30f9bf64fc649bf26f7d.png" alt="202929292.png"></p>
<p><strong>测试</strong></p>
<ul>
<li>启动前需要在nacos客户端-配置管理-配置管理栏目下有对应的yaml配置文件</li>
<li>运行cloud-config-nacos-client3377的主启动类</li>
<li>调用接口查看配置信息 - <a target="_blank" rel="noopener" href="http://localhost:3377/config/info">http://localhost:3377/config/info</a></li>
</ul>
<p><strong>自带动态刷新</strong></p>
<p>修改下Nacos中的yaml配置文件，再次调用查看配置的接口，就会发现配置已经刷新。</p>
<h4 id="Nacos之命名空间分组和DataID三者关系"><a href="#Nacos之命名空间分组和DataID三者关系" class="headerlink" title="Nacos之命名空间分组和DataID三者关系"></a>Nacos之命名空间分组和DataID三者关系</h4><p><strong>问题 - 多环境多项目管理</strong></p>
<p>问题1:</p>
<p>实际开发中，通常一个系统会准备</p>
<ol>
<li>dev开发环境</li>
<li>test测试环境</li>
<li>prod生产环境。</li>
</ol>
<p>如何保证指定环境启动时服务能正确读取到Nacos上相应环境的配置文件呢?</p>
<p>问题2:</p>
<p>一个大型分布式微服务系统会有很多微服务子项目，每个微服务项目又都会有相应的开发环境、测试环境、预发环境、正式环境…那怎么对这些微服务配置进行管理呢?</p>
<p><strong>Namespace+Group+Data lD三者关系？为什么这么设计？</strong></p>
<p>1是什么</p>
<p>类似Java里面的package名和类名最外层的namespace是可以用于区分部署环境的，Group和DatalD逻辑上区分两个目标对象。</p>
<p>2三者情况</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/60712abd615dd86ac6c119bf132a28d6.png" alt="321d10DKLJQ.png"></p>
<p>默认情况：Namespace&#x3D;public，Group&#x3D;DEFAULT_GROUP，默认Cluster是DEFAULT</p>
<ul>
<li><p>Nacos默认的Namespace是public，Namespace主要用来实现隔离。</p>
<ul>
<li>比方说我们现在有三个环境：开发、测试、生产环境，我们就可以创建三个Namespace，不同的Namespace之间是隔离的。</li>
</ul>
</li>
<li><p>Group默认是DEFAULT_GROUP，Group可以把不同的微服务划分到同一个分组里面去</p>
</li>
<li><p>Service就是微服务:一个Service可以包含多个Cluster (集群)，Nacos默认Cluster是DEFAULT，Cluster是对指定微服务的一个虚拟划分。</p>
<ul>
<li>比方说为了容灾，将Service微服务分别部署在了杭州机房和广州机房，这时就可以给杭州机房的Service微服务起一个集群名称(HZ) ，给广州机房的Service微服务起一个集群名称(GZ)，还可以尽量让同一个机房的微服务互相调用，以提升性能。</li>
</ul>
</li>
<li><p>最后是Instance，就是微服务的实例。</p>
</li>
</ul>
<h4 id="Nacos之DataID配置"><a href="#Nacos之DataID配置" class="headerlink" title="Nacos之DataID配置"></a>Nacos之DataID配置</h4><p>指定spring.profile.active和配置文件的DatalD来使不同环境下读取不同的配置</p>
<p>默认空间+默认分组+新建dev和test两个DatalD</p>
<ul>
<li>新建dev配置DatalD</li>
<li>通过spring.profile.active属性就能进行多环境下配置文件的读取</li>
</ul>
<p><strong>测试</strong></p>
<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:3377/config/info">http://localhost:3377/config/info</a></li>
<li>配置是什么就加载什么 test&#x2F;dev</li>
</ul>
<h4 id="Nacos之Group分组方案"><a href="#Nacos之Group分组方案" class="headerlink" title="Nacos之Group分组方案"></a>Nacos之Group分组方案</h4><p>通过Group实现环境区分 - 新建Group</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/bdf592aa566fe50f7f454118a70ca03c.png" alt="000.png"></p>
<p>在nacos图形界面控制台上面新建配置文件DatalD</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/28aee2b45901bbb9a6776d5c4398a6bb.png" alt="LSINFD.png"></p>
<p>bootstrap+application：在config下增加一条group的配置即可。可配置为DEV_GROUP或TEST GROUP</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/342a167a8bd948d8ba5cbfd760cf66a6.png" alt="12LADpw.png"></p>
<h4 id="Nacos之Namespace空间方案"><a href="#Nacos之Namespace空间方案" class="headerlink" title="Nacos之Namespace空间方案"></a>Nacos之Namespace空间方案</h4><p>新建dev&#x2F;test的Namespace</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/a10c71978c75c214aca5fa7057bb2834.png" alt="Djspc1223.png"></p>
<p>回到服务管理-服务列表查看</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/2a9f3fa415f5cead0219d404a47131a0.png" alt="2143)KKJ.png"></p>
<p>按照域名配置填写</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/2177c126090c0db553a8ce77e838a7c9.png" alt="wqd1MNCw.png"></p>
<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># nacos配置</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">3377</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">nacos-config-client</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">nacos:</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span> <span class="comment">#Nacos服务注册中心地址</span></span><br><span class="line">      <span class="attr">config:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span> <span class="comment">#Nacos作为配置中心地址</span></span><br><span class="line">        <span class="attr">file-extension:</span> <span class="string">yaml</span> <span class="comment">#指定yaml格式的配置</span></span><br><span class="line">        <span class="attr">group:</span> <span class="string">DEV_GROUP</span></span><br><span class="line">        <span class="attr">namespace:</span> <span class="string">7d8f0f5a-6a53-4785-9686-dd460158e5d4</span> <span class="comment">#&lt;------------指定namespace</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># $&#123;spring.application.name&#125;-$&#123;spring.profile.active&#125;.$&#123;spring.cloud.nacos.config.file-extension&#125;</span></span><br><span class="line"><span class="comment"># nacos-config-client-dev.yaml</span></span><br><span class="line"><span class="comment"># nacos-config-client-test.yaml   ----&gt; config.info</span></span><br></pre></td></tr></table></figure>

<h4 id="Nacos持久化切换配置"><a href="#Nacos持久化切换配置" class="headerlink" title="Nacos持久化切换配置"></a>Nacos持久化切换配置</h4><p>Nacos默认自带的是嵌入式数据库derby，<a target="_blank" rel="noopener" href="https://blog.csdn.net/u011863024/article/details/github.com/alibaba/nacos/blob/develop/config/pom.xml">nacos的pom.xml</a>中可以看出。</p>
<p>derby到mysql切换配置步骤：</p>
<ol>
<li>nacos-server-1.1.4\nacos\conf录下找到nacos-mysql.sql文件，执行脚本。</li>
<li>nacos-server-1.1.4\nacos\conf目录下找到application.properties，添加以下配置（按需修改对应值）。</li>
</ol>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">spring.datasource.platform=mysql</span><br><span class="line"></span><br><span class="line">db.num=1</span><br><span class="line">db.url.0=jdbc:mysql://localhost:3306/nacos_devtest?characterEncoding=utf8&amp;connectTimeout=1000&amp;socketTimeout=3000&amp;autoReconnect=true</span><br><span class="line">db.user=root</span><br><span class="line">db.password=1234</span><br></pre></td></tr></table></figure>

<p>启动Nacos，可以看到是个全新的空记录界面，以前是记录进derby。</p>
<p><strong>1.4.1版本的直接打开31-41行的注释修改为自己就行</strong></p>
<h4 id="Nacos集群配置"><a href="#Nacos集群配置" class="headerlink" title="Nacos集群配置"></a>Nacos集群配置</h4><p>这里不太会，有点问题</p>
<h3 id="Sentinel"><a href="#Sentinel" class="headerlink" title="Sentinel"></a>Sentinel</h3><h4 id="Sentinel介绍"><a href="#Sentinel介绍" class="headerlink" title="Sentinel介绍"></a>Sentinel介绍</h4><p>随着微服务的流行，服务和服务之间的稳定性变得越来越重要。<a target="_blank" rel="noopener" href="https://so.csdn.net/so/search?q=Sentinel&spm=1001.2101.3001.7020">Sentinel</a> 以流量为切入点，从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。</p>
<p>Sentinel 具有以下特征:</p>
<ul>
<li>丰富的应用场景：Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景，例如秒杀（即突发流量控制在系统容量可以承受的范围）、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。</li>
<li>完备的实时监控：Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据，甚至 500 台以下规模的集群的汇总运行情况。</li>
<li>广泛的开源生态：Sentinel 提供开箱即用的与其它开源框架&#x2F;库的整合模块，例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。</li>
<li>完善的 SPI 扩展点：Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。</li>
</ul>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/e4efa9c3547366ae4f747ad4007f6447.png" alt="12dNucx1.png"></p>
<p>—句话解释，之前我们讲解过的Hystrix</p>
<p>Hystrix与Sentinel比较：</p>
<ul>
<li>Hystrix<ol>
<li>需要我们程序员自己手工搭建监控平台</li>
<li>没有一套web界面可以给我们进行更加细粒度化得配置流控、速率控制、服务熔断、服务降级</li>
</ol>
</li>
<li>Sentinel<ol>
<li>单独一个组件，可以独立出来。</li>
<li>直接界面化的细粒度统一配置。</li>
</ol>
</li>
</ul>
<p>约定 &gt; 配置 &gt; 编码</p>
<p>都可以写在代码里面，但是我们本次还是大规模的学习使用配置和注解的方式，尽量少写代码</p>
<h4 id="Sentinel下载安装运行"><a href="#Sentinel下载安装运行" class="headerlink" title="Sentinel下载安装运行"></a>Sentinel下载安装运行</h4><p>服务使用中的各种问题：</p>
<ul>
<li>服务雪崩</li>
<li>服务降级</li>
<li>服务熔断</li>
<li>服务限流</li>
</ul>
<p>Sentinel 分为两个部分：</p>
<ul>
<li>核心库（Java 客户端）不依赖任何框架&#x2F;库，能够运行于所有 Java 运行时环境，同时对 Dubbo &#x2F; Spring Cloud 等框架也有较好的支持。</li>
<li>控制台（Dashboard）基于 Spring Boot 开发，打包后可以直接运行，不需要额外的 Tomcat 等应用容器。</li>
</ul>
<h4 id="Sentinel初始化监控"><a href="#Sentinel初始化监控" class="headerlink" title="Sentinel初始化监控"></a>Sentinel初始化监控</h4><p><strong>启动Nacos8848成功</strong></p>
<p><strong>新建工程 - cloudalibaba-sentinel-service8401</strong></p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.csp<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>sentinel-datasource-nacos<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--SpringCloud ailibaba sentinel --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-sentinel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--openfeign--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-openfeign<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- SpringBoot整合Web组件+actuator --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8401</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloudalibaba-sentinel-service</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">nacos:</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span> <span class="comment">#Nacos服务注册中心地址</span></span><br><span class="line">    <span class="attr">sentinel:</span></span><br><span class="line">      <span class="attr">transport:</span></span><br><span class="line">        <span class="attr">dashboard:</span> <span class="string">localhost:8080</span> <span class="comment">#配置Sentinel dashboard地址</span></span><br><span class="line">        <span class="attr">port:</span> <span class="number">8719</span></span><br><span class="line"></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&#x27;*&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">feign:</span></span><br><span class="line">  <span class="attr">sentinel:</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">true</span> <span class="comment"># 激活Sentinel对Feign的支持</span></span><br></pre></td></tr></table></figure>

<p>主启动类<code>@EnableDiscoveryClient</code></p>
<p>业务类FlowLimitController</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlowLimitController</span> &#123;</span><br><span class="line">    <span class="meta">@GetMapping(&quot;/testA&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">testA</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;------testA&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/testB&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">testB</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        log.info(Thread.currentThread().getName()+<span class="string">&quot;\t&quot;</span>+<span class="string">&quot;...testB&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;------testB&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>启动Sentinel8080 - <code>java -jar sentinel-dashboard-1.7.0.jar</code></strong></p>
<p><strong>启动微服务8401，查看sentienl控制台</strong></p>
<ul>
<li><p>刚启动，空空如也，啥都没有</p>
</li>
<li><p>Sentinel采用的懒加载说明</p>
<ul>
<li>执行一次访问即可<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:8401/testA">http://localhost:8401/testA</a></li>
<li><a target="_blank" rel="noopener" href="http://localhost:8401/testB">http://localhost:8401/testB</a></li>
</ul>
</li>
<li>效果 - sentinel8080正在监控微服务8401</li>
</ul>
</li>
</ul>
<h4 id="Sentinel流控规则简介"><a href="#Sentinel流控规则简介" class="headerlink" title="Sentinel流控规则简介"></a>Sentinel流控规则简介</h4><p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/d8ae2bea252af0bb278332b3aeb8fb77.png" alt="11111.png"></p>
<ul>
<li>资源名：唯一名称，默认请求路径。</li>
<li>针对来源：Sentinel可以针对调用者进行限流，填写微服务名，默认default（不区分来源）。</li>
<li>阈值类型&#x2F;单机阈值：<ul>
<li>QPS(每秒钟的请求数量)︰当调用该API的QPS达到阈值的时候，进行限流。</li>
<li>线程数：当调用该API的线程数达到阈值的时候，进行限流。</li>
</ul>
</li>
<li>是否集群：不需要集群。</li>
<li>流控模式：<ul>
<li>直接：API达到限流条件时，直接限流。</li>
<li>关联：当关联的资源达到阈值时，就限流自己。</li>
<li>链路：只记录指定链路上的流量（指定资源从入口资源进来的流量，如果达到阈值，就进行限流)【API级别的针对来源】。</li>
</ul>
</li>
<li>流控效果：<ul>
<li>快速失败：直接失败，抛异常。</li>
<li>Warm up：根据Code Factor（冷加载因子，默认3）的值，从阈值&#x2F;codeFactor，经过预热时长，才达到设置的QPS阈值。</li>
<li>排队等待：匀速排队，让请求以匀速的速度通过，阈值类型必须设置为QPS，否则无效。</li>
</ul>
</li>
</ul>
<h4 id="Sentinel流控-QPS直接失败"><a href="#Sentinel流控-QPS直接失败" class="headerlink" title="Sentinel流控-QPS直接失败"></a>Sentinel流控-QPS直接失败</h4><p><strong>直接 -&gt; 快速失败（系统默认）</strong></p>
<p><strong>配置及说明</strong></p>
<p>表示1秒钟内查询1次就是OK，若超过次数1，就直接-&gt;快速失败，报默认错误</p>
<p><strong>测试</strong></p>
<p>快速多次点击访问<a target="_blank" rel="noopener" href="http://localhost:8401/testA">http://localhost:8401/testA</a></p>
<p><strong>结果</strong></p>
<p>返回页面 Blocked by Sentinel (flow limiting)</p>
<p><strong>源码</strong></p>
<p>com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController</p>
<p><strong>思考</strong></p>
<p>直接调用默认报错信息，技术方面OK，但是，是否应该有我们自己的后续处理？类似有个fallback的兜底方法?</p>
<h4 id="Sentinel流控-线程数直接失败"><a href="#Sentinel流控-线程数直接失败" class="headerlink" title="Sentinel流控-线程数直接失败"></a>Sentinel流控-线程数直接失败</h4><p>修改FlowLimitController，给请求增加时长</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/testA&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testA</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        TimeUnit.MILLISECONDS.sleep(<span class="number">800</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;------testA&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>当有多个请求同时访问的时候搜，超过阈值就会出错</p>
<h4 id="Sentinel流控-关联"><a href="#Sentinel流控-关联" class="headerlink" title="Sentinel流控-关联"></a>Sentinel流控-关联</h4><ul>
<li>当自己关联的资源达到阈值时，就限流自己</li>
<li>当与A关联的资源B达到阀值后，就限流A自己（B惹事，A挂了）</li>
</ul>
<p><strong>设置testA</strong></p>
<p>当关联资源&#x2F;testB的QPS阀值超过1时，就限流&#x2F;testA的Rest访问地址，<strong>当关联资源到阈值后限制配置好的资源名</strong>。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/12cd41ae91ba50fe3b5525bab7bc3805.png" alt="3841.png"></p>
<p>Jmeter密集访问<a target="_blank" rel="noopener" href="http://localhost:8401/testB">localhost:8401&#x2F;testB</a>，在此期间访问<a target="_blank" rel="noopener" href="http://localhost:8401/testA">localhost:8401&#x2F;testA</a>会出现错误<code>Blocked by Sentinel(flow limiting)</code></p>
<h4 id="Sentinel流控-预热"><a href="#Sentinel流控-预热" class="headerlink" title="Sentinel流控-预热"></a>Sentinel流控-预热</h4><blockquote>
<p>默认coldFactor为3，即请求QPS 从 threshold &#x2F; 3开始，经预热时长逐渐升至设定的QPS阈值。<a target="_blank" rel="noopener" href="https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6#warm-up">link</a></p>
</blockquote>
<p><strong>源码</strong> - com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController</p>
<p>系统初始化的阀值为10&#x2F; 3约等于3,即阀值刚开始为3;然后过了5秒后阀值才慢慢升高恢复到10</p>
<p><strong>测试</strong></p>
<p>多次快速点击<a target="_blank" rel="noopener" href="http://localhost:8401/testB">http://localhost:8401/testB</a> - 刚开始不行，后续慢慢OK</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/c26846d68d79eae1e962f37942a2c99f.png" alt="IOid.png"></p>
<p><strong>应用场景</strong></p>
<p>如：秒杀系统在开启的瞬间，会有很多流量上来，很有可能把系统打死，预热方式就是把为了保护系统，可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值。</p>
<h4 id="Sentinel流控-排队等待"><a href="#Sentinel流控-排队等待" class="headerlink" title="Sentinel流控-排队等待"></a>Sentinel流控-排队等待</h4><p>匀速排队，让请求以均匀的速度通过，阀值类型必须设成QPS，否则无效。</p>
<p>设置：&#x2F;testA每秒1次请求，超过的话就排队等待，等待的超时时间为20000毫秒。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/0ddd217545dd0fe2b1f251dbea814ac2.png" alt="231000.png"></p>
<p><strong>测试</strong></p>
<ul>
<li>添加日志记录代码到FlowLimitController的testA方法</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlowLimitController</span> &#123;</span><br><span class="line">    <span class="meta">@GetMapping(&quot;/testA&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">testA</span><span class="params">()</span></span><br><span class="line">    &#123;</span><br><span class="line">        log.info(Thread.currentThread().getName()+<span class="string">&quot;\t&quot;</span>+<span class="string">&quot;...testA&quot;</span>);<span class="comment">//&lt;----</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;------testA&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>用Jmeter测试，发现后端输出是每隔一秒钟输出一个</p>
<h4 id="Sentinel降级简介"><a href="#Sentinel降级简介" class="headerlink" title="Sentinel降级简介"></a>Sentinel降级简介</h4><p><strong>熔断降级概述</strong></p>
<blockquote>
<p>除了流量控制以外，对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块，可能是另外的一个远程服务、数据库，或者第三方 API 等。例如，支付的时候，可能需要远程调用银联提供的 API；查询某个商品的价格，可能需要进行数据库查询。然而，这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况，请求的响应时间变长，那么调用服务的方法的响应时间也会变长，线程会产生堆积，最终可能耗尽业务自身的线程池，服务本身也变得不可用。</p>
<p>现代微服务架构都是分布式的，由非常多的服务组成。不同服务之间相互调用，组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定，就可能会层层级联，最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级，暂时切断不稳定调用，避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段，通常在客户端（调用端）进行配置。</p>
</blockquote>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/6a002ef360a4e5f20ee2748a092f0211.png" alt="123ddqghbb.png"></p>
<ul>
<li>RT（平均响应时间，秒级）<ul>
<li>平均响应时间 超出阈值 且 在时间窗口内通过的请求&gt;&#x3D;5，两个条件同时满足后触发降级。</li>
<li>窗口期过后关闭断路器。</li>
<li>RT最大4900（更大的需要通过-Dcsp.sentinel.statistic.max.rt&#x3D;XXXX才能生效）。</li>
</ul>
</li>
<li>异常比列（秒级）<ul>
<li>QPS &gt;&#x3D; 5且异常比例（秒级统计）超过阈值时，触发降级;时间窗口结束后，关闭降级 。</li>
</ul>
</li>
<li>异常数(分钟级)<ul>
<li>异常数(分钟统计）超过阈值时，触发降级;时间窗口结束后，关闭降级</li>
</ul>
</li>
</ul>
<p>Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时（例如调用超时或异常比例升高)，对这个资源的调用进行限制，让请求快速失败，避免影响到其它的资源而导致级联错误。</p>
<p>当资源被降级后，在接下来的降级时间窗口之内，对该资源的调用都自动熔断（默认行为是抛出 DegradeException）。</p>
<p>Sentinei的断路器是没有类似Hystrix半开状态的。(Sentinei 1.8.0 已有半开状态)</p>
<p>半开的状态系统自动去检测是否请求有异常，没有异常就关闭断路器恢复使用，有异常则继续打开断路器不可用。</p>
<h4 id="Sentinel降级-RT"><a href="#Sentinel降级-RT" class="headerlink" title="Sentinel降级-RT"></a>Sentinel降级-RT</h4><p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/dcf85d4362c017e543173c76b7dcc2a8.png" alt="20202020.png"></p>
<p><strong>注意</strong>：Sentinel 1.7.0才有<strong>平均响应时间</strong>（<code>DEGRADE_GRADE_RT</code>），Sentinel 1.8.0的没有这项，取而代之的是<strong>慢调用比例</strong> (<code>SLOW_REQUEST_RATIO</code>)。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/3a608908cef3d557322967e6bc0e5696.png" alt="087rc.png"></p>
<p>用jmter测压，一秒打10个</p>
<p>controller代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/testD&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testD</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123; </span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>); </span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123; </span><br><span class="line">        e.printStackTrace(); </span><br><span class="line">    &#125;</span><br><span class="line">    log.info(<span class="string">&quot;testD 测试RT&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>结论</strong></p>
<p>按照上述配置，永远一秒钟打进来10个线程（大于5个了）调用testD，我们希望200毫秒处理完本次任务，如果超过200毫秒还没处理完，在未来1秒钟的时间窗口内，断路器打开（保险丝跳闸）微服务不可用，保险丝跳闸断电了后续我停止jmeter，没有这么大的访问量了，断路器关闭（保险丝恢复），微服务恢复OK。</p>
<h4 id="Sentinel降级-异常比例"><a href="#Sentinel降级-异常比例" class="headerlink" title="Sentinel降级-异常比例"></a>Sentinel降级-异常比例</h4><p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/b8f35b00fffd79ef68e8f744403b92f3.png" alt="12c23.png"></p>
<p>修改controller代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/testD&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testD</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123; </span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>); </span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123; </span><br><span class="line">        e.printStackTrace(); </span><br><span class="line">    &#125;</span><br><span class="line">    log.info(<span class="string">&quot;testD 测试RT&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/ab66591ba085c32e9303d96be7b44f0d.png" alt="120dxc.png"></p>
<p>按照上述配置，单独访问一次，必然来一次报错一次(int age &#x3D; 10&#x2F;0)，调一次错一次。</p>
<p>开启jmeter后，直接高并发发送请求，多次调用达到我们的配置条件了。断路器开启(保险丝跳闸)，微服务不可用了，不再报错error而是服务降级了。</p>
<h4 id="Sentinel降级-异常数"><a href="#Sentinel降级-异常数" class="headerlink" title="Sentinel降级-异常数"></a>Sentinel降级-异常数</h4><p><strong>异常数是按照分钟统计的，时间窗口一定要大于等于60秒</strong>。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/d92c6a9ae5ed514b52ddf43fdf0d5f0e.png" alt="1211235.png"></p>
<p>添加controller代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/testE&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testE</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    log.info(<span class="string">&quot;testE 测试异常数&quot;</span>);</span><br><span class="line">    <span class="type">int</span> <span class="variable">age</span> <span class="operator">=</span> <span class="number">10</span>/<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;------testE 测试异常数&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/218fe52e19c07b30bbf4d994d05e6a8e.png" alt="b0thSJ.png"></p>
<p>访问<a target="_blank" rel="noopener" href="http://localhost:8401/testE%EF%BC%8C%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%AE%BF%E9%97%AE%E7%BB%9D%E5%AF%B9%E6%8A%A5%E9%94%99%EF%BC%8C%E5%9B%A0%E4%B8%BA%E9%99%A4%E6%95%B0%E4%B8%8D%E8%83%BD%E4%B8%BA%E9%9B%B6%EF%BC%8C%E6%88%91%E4%BB%AC%E7%9C%8B%E5%88%B0error%E7%AA%97%E5%8F%A3%EF%BC%8C%E4%BD%86%E6%98%AF%E8%BE%BE%E5%88%B05%E6%AC%A1%E6%8A%A5%E9%94%99%E5%90%8E%EF%BC%8C%E8%BF%9B%E5%85%A5%E7%86%94%E6%96%AD%E5%90%8E%E9%99%8D%E7%BA%A7%E3%80%82">http://localhost:8401/testE，第一次访问绝对报错，因为除数不能为零，我们看到error窗口，但是达到5次报错后，进入熔断后降级。</a></p>
<h4 id="Sentinel热点key-上"><a href="#Sentinel热点key-上" class="headerlink" title="Sentinel热点key(上)"></a>Sentinel热点key(上)</h4><p>何为热点？热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据，并对其访问进行限制。比如：</p>
<ul>
<li>商品 ID 为参数，统计一段时间内最常购买的商品 ID 并进行限制</li>
<li>用户 ID 为参数，针对一段时间内频繁访问的用户 ID 进行限制</li>
</ul>
<p>热点参数限流会统计传入参数中的热点参数，并根据配置的限流阈值与模式，对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制，仅对包含热点参数的资源调用生效。</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/16d2ddeff96b7cb68a064b6ec05bde25.png" alt="312sLLL.png"></p>
<p><strong>承上启下复习start</strong></p>
<p>兜底方法，分为系统默认和客户自定义，两种</p>
<p>之前的case，限流出问题后，都是用sentinel系统默认的提示: Blocked by Sentinel (flow limiting)</p>
<p>我们能不能自定？类似hystrix，某个方法出问题了，就找对应的兜底降级方法?</p>
<p>结论 - <strong>从HystrixCommand到@SentinelResource</strong></p>
<p>再contrller中添加</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/testHotKey&quot;)</span></span><br><span class="line"><span class="meta">@SentinelResource(value = &quot;testHotKey&quot;,blockHandler/*兜底方法*/ = &quot;deal_testHotKey&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">testHotKey</span><span class="params">(<span class="meta">@RequestParam(value = &quot;p1&quot;,required = false)</span> String p1,</span></span><br><span class="line"><span class="params">                         <span class="meta">@RequestParam(value = &quot;p2&quot;,required = false)</span> String p2)</span> &#123;</span><br><span class="line">    <span class="comment">//int age = 10/0;</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;------testHotKey&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*兜底方法*/</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">deal_testHotKey</span> <span class="params">(String p1, String p2, BlockException exception)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;------deal_testHotKey,o(╥﹏╥)o&quot;</span>;  <span class="comment">//sentinel系统默认的提示：Blocked by Sentinel (flow limiting)</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>配置</strong></p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/9620ee4e7e54d48ba7dda394fa1c8cd0.png" alt="dsdcopp.png"></p>
<p><strong>测试</strong></p>
<ul>
<li>error<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:8401/testHotKey?p1=abc">http://localhost:8401/testHotKey?p1=abc</a></li>
<li><a target="_blank" rel="noopener" href="http://localhost:8401/testHotKey?p1=abc&p2=33">http://localhost:8401/testHotKey?p1=abc&amp;p2=33</a></li>
</ul>
</li>
<li>right<ul>
<li><a target="_blank" rel="noopener" href="http://localhost:8401/testHotKey?p2=abc">http://localhost:8401/testHotKey?p2=abc</a></li>
</ul>
</li>
</ul>
<p>若不配置<code>@SentinelResource(value = &quot;testHotKey&quot;,blockHandler/*兜底方法*/ = &quot;deal_testHotKey&quot;)</code>的话前端就只能看到一个报错界面 </p>
<h4 id="Sentinel热点key-下"><a href="#Sentinel热点key-下" class="headerlink" title="Sentinel热点key(下)"></a>Sentinel热点key(下)</h4><p>上述案例演示了第一个参数p1，当QPS超过1秒1次点击后马上被限流。</p>
<p><strong>参数例外项</strong></p>
<ul>
<li>普通 - 超过1秒钟一个后，达到阈值1后马上被限流</li>
<li><strong>我们期望p1参数当它是某个特殊值时，它的限流值和平时不一样</strong></li>
<li>特例 - 假如当p1的值等于5时，它的阈值可以达到200</li>
</ul>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/3aa08b15109cd346a6083f080a0468fa.png" alt="dsax-ca.png"></p>
<p><strong>测试</strong></p>
<ul>
<li>right - <a target="_blank" rel="noopener" href="http://localhost:8401/testHotKey?p1=5">http://localhost:8401/testHotKey?p1=5</a></li>
<li>error - <a target="_blank" rel="noopener" href="http://localhost:8401/testHotKey?p1=3">http://localhost:8401/testHotKey?p1=3</a></li>
<li>当p1等于5的时候，阈值变为200</li>
<li>当p1不等于5的时候，阈值就是平常的1</li>
</ul>
<p><strong>前提条件</strong> - 热点参数的注意点，参数必须是基本类型或者String</p>
<p><strong>其它</strong></p>
<p>在<code>testHotKey</code>方法中添加<code>int age = 10/0;</code>使程序报错</p>
<p>将会抛出Spring Boot 2的默认异常页面，而不是兜底方法。</p>
<ul>
<li><p>@SentinelResource - 处理的是sentinel控制台配置的违规情况，有blockHandler方法配置的兜底处理;</p>
</li>
<li><p>RuntimeException int age &#x3D; 10&#x2F;0，这个是java运行时报出的运行时异常RunTimeException，@SentinelResource不管</p>
</li>
</ul>
<p>总结 - @SentinelResource主管配置出错，运行出错该走异常走异常</p>
<h4 id="Sentinel系统规则"><a href="#Sentinel系统规则" class="headerlink" title="Sentinel系统规则"></a>Sentinel系统规则</h4><p>就是一次性对所有接口进行限制</p>
<p>系统保护规则是从应用级别的入口流量进行控制，从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标，让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。</p>
<ul>
<li>Load 自适应（仅对 Linux&#x2F;Unix-like 机器生效）：系统的 load1 作为启发指标，进行自适应系统保护。当系统 load1 超过设定的启发值，且系统当前的并发线程数超过估算的系统容量时才会触发系统保护（BBR 阶段）。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。</li>
<li>CPU usage（1.5.0+ 版本）：当系统 CPU 使用率超过阈值即触发系统保护（取值范围 0.0-1.0），比较灵敏。</li>
<li>平均 RT：当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护，单位是毫秒。</li>
<li>并发线程数：当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。</li>
<li>入口 QPS：当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。</li>
</ul>
<h4 id="SentinelResource配置-上"><a href="#SentinelResource配置-上" class="headerlink" title="SentinelResource配置(上)"></a>SentinelResource配置(上)</h4><p><em>按资源名称限流 + 后续处理</em></p>
<p><strong>启动Nacos成功</strong></p>
<p><strong>启动Sentinel成功</strong></p>
<p><strong>Module - cloudalibaba-sentinel-service8401</strong></p>
<p>controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RateLimitController</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@GetMapping(&quot;/byResource&quot;)</span></span><br><span class="line">    <span class="meta">@SentinelResource(value = &quot;byResource&quot;,blockHandler = &quot;handleException&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult <span class="title function_">byResource</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>(<span class="number">200</span>,<span class="string">&quot;按资源名称限流测试OK&quot;</span>,<span class="keyword">new</span> <span class="title class_">Payment</span>(<span class="number">2020L</span>,<span class="string">&quot;serial001&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> CommonResult <span class="title function_">handleException</span><span class="params">(BlockException exception)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>(<span class="number">444</span>,exception.getClass().getCanonicalName()+<span class="string">&quot;\t 服务不可用&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>配置流控规则</strong></p>
<p>配置步骤</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/91aa0ac210011218db9557a2bfcfebd1.png" alt="21100101.png"></p>
<p>图形配置和代码关系</p>
<p>表示1秒钟内查询次数大于1，就跑到我们自定义的处流，限流</p>
<p><strong>测试</strong></p>
<p>1秒钟点击1下，OK</p>
<p>超过上述，疯狂点击，返回了自己定义的限流处理信息，限流发生</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span><span class="attr">&quot;code&quot;</span><span class="punctuation">:</span><span class="number">444</span><span class="punctuation">,</span> <span class="attr">&quot;message&quot;</span><span class="punctuation">:</span><span class="string">&quot;com.alibaba.csp.sentinel.slots.block.flow.FlowException\t 服务不可用&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;data&quot;</span><span class="punctuation">:</span><span class="literal"><span class="keyword">null</span></span><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure>

<p><strong>额外问题</strong></p>
<p>此时关闭问服务8401 -&gt; Sentinel控制台，流控规则消失了</p>
<hr>
<p><em>按照Url地址限流 + 后续处理</em></p>
<p><strong>通过访问的URL来限流，会返回Sentinel自带默认的限流处理信息</strong></p>
<p><strong>业务类RateLimitController</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/rateLimit/byUrl&quot;)</span></span><br><span class="line"><span class="meta">@SentinelResource(value = &quot;byUrl&quot;)</span></span><br><span class="line"><span class="keyword">public</span> CommonResult <span class="title function_">byUrl</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>(<span class="number">200</span>,<span class="string">&quot;按url限流测试OK&quot;</span>,<span class="keyword">new</span> <span class="title class_">Payment</span>(<span class="number">2020L</span>,<span class="string">&quot;serial002&quot;</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>Sentinel控制台配置</strong></p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/d6a79b7cc3f2f9c8b6dcbe3f77f78c6b.png" alt="1xll.png"></p>
<p><strong>测试</strong></p>
<ul>
<li>快速点击<a target="_blank" rel="noopener" href="http://localhost:8401/rateLimit/byUrl">http://localhost:8401/rateLimit/byUrl</a></li>
<li>结果 - 会返回Sentinel自带的限流处理结果 <code>Blocked by Sentinel (flow limiting)</code></li>
</ul>
<p><strong>上面兜底方案面临的问题</strong></p>
<ol>
<li>系统默认的，没有体现我们自己的业务要求。</li>
<li>依照现有条件，我们自定义的处理方法又和业务代码耦合在一块，不直观。</li>
<li>每个业务方法都添加—个兜底的，那代码膨胀加剧。</li>
<li>全局统—的处理方法没有体现。</li>
</ol>
<h4 id="SentinelResource配置-中"><a href="#SentinelResource配置-中" class="headerlink" title="SentinelResource配置(中)"></a>SentinelResource配置(中)</h4><p>客户自定义限流处理逻辑</p>
<p>自定义限流处理类 - 创建<code>CustomerBlockHandler</code>类用于自定义限流处理逻辑</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.csp.sentinel.slots.block.BlockException;</span><br><span class="line"><span class="keyword">import</span> com.atguigu.springcloud.entities.CommonResult;</span><br><span class="line"><span class="keyword">import</span> com.atguigu.springcloud.entities.Payment;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomerBlockHandler</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> CommonResult <span class="title function_">handlerException</span><span class="params">(BlockException exception)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>(<span class="number">4444</span>,<span class="string">&quot;按客戶自定义,global handlerException----1&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> CommonResult <span class="title function_">handlerException2</span><span class="params">(BlockException exception)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>(<span class="number">4444</span>,<span class="string">&quot;按客戶自定义,global handlerException----2&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>RateLimitController</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/rateLimit/customerBlockHandler&quot;)</span></span><br><span class="line"><span class="meta">@SentinelResource(value = &quot;customerBlockHandler&quot;,</span></span><br><span class="line"><span class="meta">        blockHandlerClass = CustomerBlockHandler.class,//&lt;-------- 自定义限流处理类</span></span><br><span class="line"><span class="meta">        blockHandler = &quot;handlerException2&quot;)</span><span class="comment">//&lt;-----------</span></span><br><span class="line"><span class="keyword">public</span> CommonResult <span class="title function_">customerBlockHandler</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>(<span class="number">200</span>,<span class="string">&quot;按客戶自定义&quot;</span>,<span class="keyword">new</span> <span class="title class_">Payment</span>(<span class="number">2020L</span>,<span class="string">&quot;serial003&quot;</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Sentinel控制台配置</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/44dccf4107a74fda56f0807d39fa53f1.png" alt="1114-123d.png"></p>
<p>启动微服务后先调用一次 - <a target="_blank" rel="noopener" href="http://localhost:8401/rateLimit/customerBlockHandler%E3%80%82%E7%84%B6%E5%90%8E%EF%BC%8C%E5%A4%9A%E6%AC%A1%E5%BF%AB%E9%80%9F%E5%88%B7%E6%96%B0http://localhost:8401/rateLimit/customerBlockHandler%E3%80%82%E5%88%B7%E6%96%B0%E5%90%8E%EF%BC%8C%E6%88%91%E4%BB%AC%E8%87%AA%E5%AE%9A%E4%B9%89%E5%85%9C%E5%BA%95%E6%96%B9%E6%B3%95%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%BF%A1%E6%81%AF%E5%B0%B1%E8%BF%94%E5%9B%9E%E5%88%B0%E5%89%8D%E7%AB%AF%E3%80%82">http://localhost:8401/rateLimit/customerBlockHandler。然后，多次快速刷新http://localhost:8401/rateLimit/customerBlockHandler。刷新后，我们自定义兜底方法的字符串信息就返回到前端。</a></p>
<h4 id="SentinelResource配置-下"><a href="#SentinelResource配置-下" class="headerlink" title="SentinelResource配置(下)"></a>SentinelResource配置(下)</h4><p><strong>@SentinelResource 注解</strong></p>
<blockquote>
<p>注意：注解方式埋点不支持 private 方法。</p>
</blockquote>
<p>@SentinelResource<code>用于定义资源，并提供可选的异常处理和 fallback 配置项。 </code>@SentinelResource&#96; 注解包含以下属性：</p>
<ul>
<li>value：资源名称，必需项（不能为空）</li>
<li>entryType：entry 类型，可选项（默认为 EntryType.OUT）</li>
<li>blockHandler &#x2F; blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称，可选项。blockHandler 函数访问范围需要是 public，返回类型需要与原方法相匹配，参数类型需要和原方法相匹配并且最后加一个额外的参数，类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 blockHandlerClass 为对应的类的 Class 对象，注意对应的函数必需为 static 函数，否则无法解析。若本次访问被限流或服务降级，则调用blockHandler指定的接口。</li>
<li>fallback &#x2F;fallbackClass：fallback 函数名称，可选项，用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常（除了exceptionsToIgnore里面排除掉的异常类型）进行处理。若本接口出现未知异常，则调用fallback指定的接口。fallback 函数签名和位置要求：<ul>
<li>返回值类型必须与原函数返回值类型一致；</li>
<li>方法参数列表需要和原函数一致，或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。</li>
<li>fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 fallbackClass 为对应的类的 Class 对象，注意对应的函数必需为 static 函数，否则无法解析。</li>
</ul>
</li>
<li>defaultFallback（since 1.6.0）：默认的 fallback 函数名称，可选项，通常用于通用的 fallback 逻辑（即可以用于很多服务或方法）。默认 fallback 函数可以针对所有类型的异常（除了exceptionsToIgnore里面排除掉的异常类型）进行处理。若同时配置了 fallback 和 defaultFallback，则只有 fallback 会生效。defaultFallback 函数签名要求：<ul>
<li>返回值类型必须与原函数返回值类型一致；</li>
<li>方法参数列表需要为空，或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。</li>
<li>defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 fallbackClass 为对应的类的 Class 对象，注意对应的函数必需为 static 函数，否则无法解析。</li>
</ul>
</li>
<li><code>exceptionsToIgnore</code>（since 1.6.0）：用于指定哪些异常被排除掉，不会计入异常统计中，也不会进入 fallback 逻辑中，而是会原样抛出。</li>
</ul>
<p>Sentinel主要有三个核心Api：</p>
<ol>
<li>SphU定义资源</li>
<li>Tracer定义统计</li>
<li>ContextUtil定义了上下文</li>
</ol>
<h4 id="Sentinel服务熔断Ribbon环境预说"><a href="#Sentinel服务熔断Ribbon环境预说" class="headerlink" title="Sentinel服务熔断Ribbon环境预说"></a>Sentinel服务熔断Ribbon环境预说</h4><p>sentinel整合ribbon+openFeign+fallback</p>
<p>Ribbon系列</p>
<ul>
<li>启动nacos和sentinel</li>
<li>提供者9003&#x2F;9004</li>
<li>消费者84</li>
</ul>
<hr>
<p><strong>提供者9003&#x2F;9004</strong></p>
<p>新建cloudalibaba-provider-payment9003&#x2F;9004，两个一样的做法</p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--SpringCloud ailibaba nacos --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span><span class="comment">&lt;!-- 引入自己定义的api通用包，可以使用Payment支付Entity --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.atguigu.springcloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>cloud-api-commons<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;project.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- SpringBoot整合Web组件 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--日常通用jar包配置--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-devtools<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">scope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">9003</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">nacos-payment-provider</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">nacos:</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span> <span class="comment">#配置Nacos地址</span></span><br><span class="line"></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&#x27;*&#x27;</span></span><br></pre></td></tr></table></figure>

<p><strong>记得修改不同的端口号</strong></p>
<p>主启动添加<code>@EnableDiscoveryClient</code></p>
<p>业务类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentController</span> &#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;server.port&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String serverPort;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//模拟数据库</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> HashMap&lt;Long,Payment&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">    <span class="keyword">static</span></span><br><span class="line">    &#123;</span><br><span class="line">        hashMap.put(<span class="number">1L</span>,<span class="keyword">new</span> <span class="title class_">Payment</span>(<span class="number">1L</span>,<span class="string">&quot;28a8c1e3bc2742d8848569891fb42181&quot;</span>));</span><br><span class="line">        hashMap.put(<span class="number">2L</span>,<span class="keyword">new</span> <span class="title class_">Payment</span>(<span class="number">2L</span>,<span class="string">&quot;bba8c1e3bc2742d8848569891ac32182&quot;</span>));</span><br><span class="line">        hashMap.put(<span class="number">3L</span>,<span class="keyword">new</span> <span class="title class_">Payment</span>(<span class="number">3L</span>,<span class="string">&quot;6ua8c1e3bc2742d8848569891xt92183&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(value = &quot;/paymentSQL/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">paymentSQL</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Long id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">Payment</span> <span class="variable">payment</span> <span class="operator">=</span> hashMap.get(id);</span><br><span class="line">        CommonResult&lt;Payment&gt; result = <span class="keyword">new</span> <span class="title class_">CommonResult</span>(<span class="number">200</span>,<span class="string">&quot;from mysql,serverPort:  &quot;</span>+serverPort,payment);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试地址 - <a target="_blank" rel="noopener" href="http://localhost:9003/paymentSQL/1">http://localhost:9003/paymentSQL/1</a></p>
<hr>
<p><strong>消费者84</strong></p>
<p>新建cloudalibaba-consumer-nacos-order84</p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--SpringCloud openfeign --&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    &lt;dependency&gt;</span></span><br><span class="line"><span class="comment">        &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;</span></span><br><span class="line"><span class="comment">        &lt;artifactId&gt;spring-cloud-starter-openfeign&lt;/artifactId&gt;</span></span><br><span class="line"><span class="comment">    &lt;/dependency&gt;</span></span><br><span class="line"><span class="comment">	--&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--SpringCloud ailibaba nacos --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--SpringCloud ailibaba sentinel --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-alibaba-sentinel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 引入自己定义的api通用包，可以使用Payment支付Entity --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.atguigu.springcloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>cloud-api-commons<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;project.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- SpringBoot整合Web组件 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--日常通用jar包配置--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-devtools<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">scope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">84</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">nacos-order-consumer</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">nacos:</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span></span><br><span class="line">    <span class="attr">sentinel:</span></span><br><span class="line">      <span class="attr">transport:</span></span><br><span class="line">        <span class="comment">#配置Sentinel dashboard地址</span></span><br><span class="line">        <span class="attr">dashboard:</span> <span class="string">localhost:8080</span></span><br><span class="line">        <span class="comment">#默认8719端口，假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口</span></span><br><span class="line">        <span class="attr">port:</span> <span class="number">8719</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)</span></span><br><span class="line"><span class="attr">service-url:</span></span><br><span class="line">  <span class="attr">nacos-user-service:</span> <span class="string">http://nacos-payment-provider</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 激活Sentinel对Feign的支持</span></span><br><span class="line"><span class="attr">feign:</span></span><br><span class="line">  <span class="attr">sentinel:</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure>

<p>主启动</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableDiscoveryClient</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span></span><br></pre></td></tr></table></figure>

<p>ApplicationContextConfig</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ApplicationContextConfig</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@LoadBalanced</span></span><br><span class="line">    <span class="keyword">public</span> RestTemplate <span class="title function_">getRestTemplate</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>CircleBreakerController</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CircleBreakerController</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">SERVICE_URL</span> <span class="operator">=</span> <span class="string">&quot;http://nacos-payment-provider&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/consumer/fallback/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="meta">@SentinelResource(value = &quot;fallback&quot;)</span><span class="comment">//没有配置</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">fallback</span><span class="params">(<span class="meta">@PathVariable</span> Long id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        CommonResult&lt;Payment&gt; result = restTemplate.getForObject(SERVICE_URL + <span class="string">&quot;/paymentSQL/&quot;</span>+id,CommonResult.class,id);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (id == <span class="number">4</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span> (<span class="string">&quot;IllegalArgumentException,非法参数异常....&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span> (result.getData() == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span> (<span class="string">&quot;NullPointerException,该ID没有对应记录,空指针异常&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>修改后请重启微服务</p>
<ul>
<li>热部署对java代码级生效及时</li>
<li>对@SentinelResource注解内属性，有时效果不好</li>
</ul>
<p>目的</p>
<ul>
<li>fallback管运行异常</li>
<li>blockHandler管配置违规</li>
</ul>
<p>测试地址 - <a target="_blank" rel="noopener" href="http://localhost:84/consumer/fallback/1">http://localhost:84/consumer/fallback/1</a></p>
<p>没有任何配置</p>
<p>只配置fallback</p>
<p>只配置blockHandler</p>
<p>fallback和blockHandler都配置</p>
<p>忽略属性</p>
<h4 id="Sentinel服务熔断只配置fallback"><a href="#Sentinel服务熔断只配置fallback" class="headerlink" title="Sentinel服务熔断只配置fallback"></a>Sentinel服务熔断只配置fallback</h4><p>为了防止出现程序报错页面，添加兜底方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CircleBreakerController</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">SERVICE_URL</span> <span class="operator">=</span> <span class="string">&quot;http://nacos-payment-provider&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/consumer/fallback/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="comment">//@SentinelResource(value = &quot;fallback&quot;)//没有配置</span></span><br><span class="line">    <span class="meta">@SentinelResource(value = &quot;fallback&quot;, fallback = &quot;handlerFallback&quot;)</span> <span class="comment">//fallback只负责业务异常</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">fallback</span><span class="params">(<span class="meta">@PathVariable</span> Long id)</span> &#123;</span><br><span class="line">        CommonResult&lt;Payment&gt; result = restTemplate.getForObject(SERVICE_URL + <span class="string">&quot;/paymentSQL/&quot;</span>+id,CommonResult.class,id);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (id == <span class="number">4</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span> (<span class="string">&quot;IllegalArgumentException,非法参数异常....&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span> (result.getData() == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span> (<span class="string">&quot;NullPointerException,该ID没有对应记录,空指针异常&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//本例是fallback</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult <span class="title function_">handlerFallback</span><span class="params">(<span class="meta">@PathVariable</span>  Long id,Throwable e)</span> &#123;</span><br><span class="line">        <span class="type">Payment</span> <span class="variable">payment</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Payment</span>(id,<span class="string">&quot;null&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>&lt;&gt;(<span class="number">444</span>,<span class="string">&quot;兜底异常handlerFallback,exception内容  &quot;</span>+e.getMessage(),payment);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="Sentinel服务熔断只配置blockHandler"><a href="#Sentinel服务熔断只配置blockHandler" class="headerlink" title="Sentinel服务熔断只配置blockHandler"></a>Sentinel服务熔断只配置blockHandler</h4><p>blockHandler只负责<strong>sentinel控制台配置违规</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CircleBreakerController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">SERVICE_URL</span> <span class="operator">=</span> <span class="string">&quot;http://nacos-payment-provider&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/consumer/fallback/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="comment">//@SentinelResource(value = &quot;fallback&quot;) //没有配置</span></span><br><span class="line">    <span class="comment">//@SentinelResource(value = &quot;fallback&quot;,fallback = &quot;handlerFallback&quot;) //fallback只负责业务异常</span></span><br><span class="line">    <span class="meta">@SentinelResource(value = &quot;fallback&quot;,blockHandler = &quot;blockHandler&quot;)</span> <span class="comment">//blockHandler只负责sentinel控制台配置违规</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">fallback</span><span class="params">(<span class="meta">@PathVariable</span> Long id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        CommonResult&lt;Payment&gt; result = restTemplate.getForObject(SERVICE_URL + <span class="string">&quot;/paymentSQL/&quot;</span>+id,CommonResult.class,id);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (id == <span class="number">4</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span> (<span class="string">&quot;IllegalArgumentException,非法参数异常....&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span> (result.getData() == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span> (<span class="string">&quot;NullPointerException,该ID没有对应记录,空指针异常&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//本例是fallback</span></span><br><span class="line"><span class="comment">/*    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) &#123;</span></span><br><span class="line"><span class="comment">        Payment payment = new Payment(id,&quot;null&quot;);</span></span><br><span class="line"><span class="comment">        return new CommonResult&lt;&gt;(444,&quot;兜底异常handlerFallback,exception内容  &quot;+e.getMessage(),payment);</span></span><br><span class="line"><span class="comment">    &#125;*/</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//本例是blockHandler</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult <span class="title function_">blockHandler</span><span class="params">(<span class="meta">@PathVariable</span>  Long id,BlockException blockException)</span> &#123;</span><br><span class="line">        <span class="type">Payment</span> <span class="variable">payment</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Payment</span>(id,<span class="string">&quot;null&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>&lt;&gt;(<span class="number">445</span>,<span class="string">&quot;blockHandler-sentinel限流,无此流水: blockException  &quot;</span>+blockException.getMessage(),payment);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="Sentinel服务熔断fallback和blockHandler都配置"><a href="#Sentinel服务熔断fallback和blockHandler都配置" class="headerlink" title="Sentinel服务熔断fallback和blockHandler都配置"></a>Sentinel服务熔断fallback和blockHandler都配置</h4><p>若blockHandler和fallback都进行了配置，则被限流降级而抛出BlockException时只会进入blockHandler处理逻辑。</p>
<p>异常访问会走handlerFallback，若设置了限流的话，多次访问会走blockHandler</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CircleBreakerController</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">SERVICE_URL</span> <span class="operator">=</span> <span class="string">&quot;http://nacos-payment-provider&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/consumer/fallback/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="comment">//@SentinelResource(value = &quot;fallback&quot;) //没有配置</span></span><br><span class="line">    <span class="comment">//@SentinelResource(value = &quot;fallback&quot;,fallback = &quot;handlerFallback&quot;) //fallback只负责业务异常</span></span><br><span class="line">    <span class="comment">//@SentinelResource(value = &quot;fallback&quot;,blockHandler = &quot;blockHandler&quot;) //blockHandler只负责sentinel控制台配置违规</span></span><br><span class="line">    <span class="meta">@SentinelResource(value = &quot;fallback&quot;,fallback = &quot;handlerFallback&quot;,blockHandler = &quot;blockHandler&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">fallback</span><span class="params">(<span class="meta">@PathVariable</span> Long id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        CommonResult&lt;Payment&gt; result = restTemplate.getForObject(SERVICE_URL + <span class="string">&quot;/paymentSQL/&quot;</span>+id,CommonResult.class,id);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (id == <span class="number">4</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span> (<span class="string">&quot;IllegalArgumentException,非法参数异常....&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span> (result.getData() == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span> (<span class="string">&quot;NullPointerException,该ID没有对应记录,空指针异常&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//本例是fallback</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult <span class="title function_">handlerFallback</span><span class="params">(<span class="meta">@PathVariable</span>  Long id,Throwable e)</span> &#123;</span><br><span class="line">        <span class="type">Payment</span> <span class="variable">payment</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Payment</span>(id,<span class="string">&quot;null&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>&lt;&gt;(<span class="number">444</span>,<span class="string">&quot;兜底异常handlerFallback,exception内容  &quot;</span>+e.getMessage(),payment);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//本例是blockHandler</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult <span class="title function_">blockHandler</span><span class="params">(<span class="meta">@PathVariable</span>  Long id,BlockException blockException)</span> &#123;</span><br><span class="line">        <span class="type">Payment</span> <span class="variable">payment</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Payment</span>(id,<span class="string">&quot;null&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>&lt;&gt;(<span class="number">445</span>,<span class="string">&quot;blockHandler-sentinel限流,无此流水: blockException  &quot;</span>+blockException.getMessage(),payment);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="Sentinel服务熔断exceptionsToIgnore"><a href="#Sentinel服务熔断exceptionsToIgnore" class="headerlink" title="Sentinel服务熔断exceptionsToIgnore"></a>Sentinel服务熔断exceptionsToIgnore</h4><p>exceptionsToIgnore，忽略指定异常，即这些异常不用兜底方法处理。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CircleBreakerController</span>    </span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@RequestMapping(&quot;/consumer/fallback/&#123;id&#125;&quot;)</span></span><br><span class="line">    <span class="meta">@SentinelResource(value = &quot;fallback&quot;,fallback = &quot;handlerFallback&quot;,blockHandler = &quot;blockHandler&quot;,</span></span><br><span class="line"><span class="meta">            exceptionsToIgnore = &#123;IllegalArgumentException.class&#125;)</span><span class="comment">//&lt;-------------</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">fallback</span><span class="params">(<span class="meta">@PathVariable</span> Long id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        CommonResult&lt;Payment&gt; result = restTemplate.getForObject(SERVICE_URL + <span class="string">&quot;/paymentSQL/&quot;</span>+id,CommonResult.class,id);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (id == <span class="number">4</span>) &#123;</span><br><span class="line">            <span class="comment">//exceptionsToIgnore属性有IllegalArgumentException.class，</span></span><br><span class="line">            <span class="comment">//所以IllegalArgumentException不会跳入指定的兜底程序。</span></span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span> (<span class="string">&quot;IllegalArgumentException,非法参数异常....&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span> (result.getData() == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span> (<span class="string">&quot;NullPointerException,该ID没有对应记录,空指针异常&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">	...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="Sentinel服务熔断OpenFeign"><a href="#Sentinel服务熔断OpenFeign" class="headerlink" title="Sentinel服务熔断OpenFeign"></a>Sentinel服务熔断OpenFeign</h4><p><strong>修改84模块</strong></p>
<ul>
<li>84消费者调用提供者9003</li>
<li>Feign组件一般是消费侧</li>
</ul>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--SpringCloud openfeign --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-openfeign<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 激活Sentinel对Feign的支持</span></span><br><span class="line"><span class="attr">feign:</span></span><br><span class="line">  <span class="attr">sentinel:</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>

<p>业务类</p>
<p>带@Feignclient注解的业务接口，fallback &#x3D; PaymentFallbackService.class</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">@FeignClient(value = &quot;nacos-payment-provider&quot;,fallback = PaymentFallbackService.class)</span><br><span class="line">public interface PaymentService</span><br><span class="line">&#123;</span><br><span class="line">    @GetMapping(value = &quot;/paymentSQL/&#123;id&#125;&quot;)</span><br><span class="line">    public CommonResult&lt;Payment&gt; paymentSQL(@PathVariable(&quot;id&quot;) Long id);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PaymentFallbackService</span> <span class="keyword">implements</span> <span class="title class_">PaymentService</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">paymentSQL</span><span class="params">(Long id)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonResult</span>&lt;&gt;(<span class="number">44444</span>,<span class="string">&quot;服务降级返回,---PaymentFallbackService&quot;</span>,<span class="keyword">new</span> <span class="title class_">Payment</span>(id,<span class="string">&quot;errorSerial&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Resource</span></span><br><span class="line"><span class="keyword">private</span> PaymentService paymentService;</span><br><span class="line"><span class="meta">@GetMapping(value = &quot;/consumer/paymentSQL/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> CommonResult&lt;Payment&gt; <span class="title function_">paymentSQL</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Long id)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> paymentService.paymentSQL(id);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>主启动</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.discovery.EnableDiscoveryClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span><span class="comment">//&lt;------------------------</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderNacosMain84</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        SpringApplication.run(OrderNacosMain84.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试 - <a target="_blank" rel="noopener" href="http://localhost:84/consumer/paymentSQL/1">http://localhost:84/consumer/paymentSQL/1</a></p>
<p>测试84调用9003，此时故意关闭9003微服务提供者，<strong>84消费侧自动降级</strong>，不会被耗死。</p>
<p><strong>熔断框架比较</strong></p>
<p><a target="_blank" rel="noopener" href="https://imgse.com/i/pPFrBUP"><img src="" data-original="https://s1.ax1x.com/2023/08/04/pPFrBUP.png" alt="pPFrBUP.png"></a></p>
<h4 id="Sentinel持久化规则"><a href="#Sentinel持久化规则" class="headerlink" title="Sentinel持久化规则"></a>Sentinel持久化规则</h4><p><strong>是什么</strong></p>
<p>一旦我们重启应用，sentinel规则将消失，生产环境需要将配置规则进行持久化。</p>
<p><strong>怎么玩</strong></p>
<p>将限流配置规则持久化进Nacos保存，只要刷新8401某个rest地址，sentinel控制台的流控规则就能看到，只要Nacos里面的配置不删除，针对8401上sentinel上的流控规则持续有效。</p>
<p><strong>步骤</strong></p>
<p>修改cloudalibaba-sentinel-service8401</p>
<p>POM</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba.csp<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>sentinel-datasource-nacos<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>YML</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8401</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">cloudalibaba-sentinel-service</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">nacos:</span></span><br><span class="line">      <span class="attr">discovery:</span></span><br><span class="line">        <span class="attr">server-addr:</span> <span class="string">localhost:8848</span> <span class="comment">#Nacos服务注册中心地址</span></span><br><span class="line">    <span class="attr">sentinel:</span></span><br><span class="line">      <span class="attr">transport:</span></span><br><span class="line">        <span class="attr">dashboard:</span> <span class="string">localhost:8080</span> <span class="comment">#配置Sentinel dashboard地址</span></span><br><span class="line">        <span class="attr">port:</span> <span class="number">8719</span></span><br><span class="line">      <span class="attr">datasource:</span> <span class="comment">#&lt;---------------------------关注点，添加Nacos数据源配置</span></span><br><span class="line">        <span class="attr">ds1:</span></span><br><span class="line">          <span class="attr">nacos:</span></span><br><span class="line">            <span class="attr">server-addr:</span> <span class="string">localhost:8848</span></span><br><span class="line">            <span class="attr">dataId:</span> <span class="string">cloudalibaba-sentinel-service</span></span><br><span class="line">            <span class="attr">groupId:</span> <span class="string">DEFAULT_GROUP</span></span><br><span class="line">            <span class="attr">data-type:</span> <span class="string">json</span></span><br><span class="line">            <span class="attr">rule-type:</span> <span class="string">flow</span></span><br><span class="line"></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&#x27;*&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">feign:</span></span><br><span class="line">  <span class="attr">sentinel:</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">true</span> <span class="comment"># 激活Sentinel对Feign的支持</span></span><br></pre></td></tr></table></figure>

<p>添加Nacos业务规则配置</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/2401a6b2df715ee64f647da2f31e1eeb.png" alt="214PPPP.png"></p>
<p>配置内容解析</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">[&#123;</span><br><span class="line">    &quot;resource&quot;: &quot;/rateLimit/byUrl&quot;,</span><br><span class="line">    &quot;limitApp&quot;: &quot;default&quot;,</span><br><span class="line">    &quot;grade&quot;: 1,</span><br><span class="line">    &quot;count&quot;: 1, </span><br><span class="line">    &quot;strategy&quot;: 0,</span><br><span class="line">    &quot;controlBehavior&quot;: 0,</span><br><span class="line">    &quot;clusterMode&quot;: false</span><br><span class="line">&#125;]</span><br></pre></td></tr></table></figure>

<ul>
<li>resource：资源名称；</li>
<li>limitApp：来源应用；</li>
<li>grade：阈值类型，0表示线程数, 1表示QPS；</li>
<li>count：单机阈值；</li>
<li>strategy：流控模式，0表示直接，1表示关联，2表示链路；</li>
<li>controlBehavior：流控效果，0表示快速失败，</li>
<li>1表示Warm Up，2表示排队等待；</li>
<li>clusterMode：是否集群。</li>
</ul>
<p>启动8401后刷新sentinel发现业务规则有了</p>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/c854e986254c09d0a7866811ec1e0cb4.png" alt="0-0-0-wqq.png"></p>
<p>快速访问测试接口 - <a target="_blank" rel="noopener" href="http://localhost:8401/rateLimit/byUrl">http://localhost:8401/rateLimit/byUrl</a> - 页面返回<code>Blocked by Sentinel (flow limiting)</code></p>
<p>停止8401再看sentinel - 停机后发现流控规则没有了</p>
<p>重新启动8401再看sentinel</p>
<ul>
<li>乍一看还是没有，稍等一会儿</li>
<li>多次调用 - <a target="_blank" rel="noopener" href="http://localhost:8401/rateLimit/byUrl">http://localhost:8401/rateLimit/byUrl</a></li>
<li>重新配置出现了，持久化验证通过</li>
</ul>
<h3 id="Seata"><a href="#Seata" class="headerlink" title="Seata"></a>Seata</h3><h4 id="分布式事务问题由来"><a href="#分布式事务问题由来" class="headerlink" title="分布式事务问题由来"></a>分布式事务问题由来</h4><p>分布式前</p>
<ul>
<li>单机单库没这个问题</li>
<li>从1:1 -&gt; 1:N -&gt; N:N</li>
</ul>
<p>单体应用被拆分成微服务应用，原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源，业务操作需要调用三三 个服务来完成。此时<strong>每个服务内部的数据一致性由本地事务来保证， 但是全局的数据一致性问题没法保证</strong>。</p>
<p>一句话：<strong>一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用，就会产生分布式事务问题</strong>。</p>
<h4 id="Seata术语"><a href="#Seata术语" class="headerlink" title="Seata术语"></a>Seata术语</h4><p>Seata是一款开源的分布式事务解决方案，致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p>
<p><strong>能干嘛</strong></p>
<p>一个典型的分布式事务过程</p>
<p>分布式事务处理过程的一ID+三组件模型：</p>
<ul>
<li>Transaction ID XID 全局唯一的事务ID</li>
<li>三组件概念<ul>
<li>TC (Transaction Coordinator) - 事务协调者：维护全局和分支事务的状态，驱动全局事务提交或回滚。</li>
<li>TM (Transaction Manager) - 事务管理器：定义全局事务的范围：开始全局事务、提交或回滚全局事务。</li>
<li>RM (Resource Manager) - 资源管理器：管理分支事务处理的资源，与TC交谈以注册分支事务和报告分支事务的状态，并驱动分支事务提交或回滚。</li>
</ul>
</li>
</ul>
<p>处理过程：</p>
<ul>
<li>TM向TC申请开启一个全局事务，全局事务创建成功并生成一个全局唯一的XID；</li>
<li>XID在微服务调用链路的上下文中传播；</li>
<li>RM向TC注册分支事务，将其纳入XID对应全局事务的管辖；</li>
<li>TM向TC发起针对XID的全局提交或回滚决议；</li>
<li>TC调度XID下管辖的全部分支事务完成提交或回滚请求。</li>
</ul>
<p><img src="" data-original="https://img-blog.csdnimg.cn/img_convert/2d2c6aa29c3158413f66d4ef8c1000dc.png" alt="cnaois.png"></p>
<h4 id="Seata-Server安装"><a href="#Seata-Server安装" class="headerlink" title="Seata-Server安装"></a>Seata-Server安装</h4><p><strong>下载</strong></p>
<p><a target="_blank" rel="noopener" href="https://github.com/seata/seata/releases/">Releases · seata&#x2F;seata (github.com)</a></p>
<p><strong>怎么玩</strong></p>
<p>本地@Transactional</p>
<p>全局@GlobalTransactional<br><strong>SEATA 的分布式交易解决方案</strong></p>
<p>我们只需要使用一个 <code>@GlobalTransactional</code> 注解在业务方法上</p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta"><i class="fas fa-circle-user fa-fw"></i>文章作者: </span><span class="post-copyright-info"><a href="http://www.lijunxi.site">Jixer</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta"><i class="fas fa-square-arrow-up-right fa-fw"></i>文章链接: </span><span class="post-copyright-info"><a href="http://www.lijunxi.site/posts/1476420007/">http://www.lijunxi.site/posts/1476420007/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta"><i class="fas fa-circle-exclamation fa-fw"></i>版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="http://www.lijunxi.site" target="_blank">Jixer的小屋</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/SpringCloud/">SpringCloud</a></div><div class="post_share"><div class="social-share" data-image="https://q1.qlogo.cn/g?b=qq&amp;nk=2770063826&amp;s=640" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="/pluginsSrc/butterfly-extsrc/sharejs/dist/css/share.min.css?v=1.1.3" media="print" onload="this.media='all'"><script src="/pluginsSrc/butterfly-extsrc/sharejs/dist/js/social-share.min.js?v=1.1.3" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/posts/2960345248/" title="MiniShell"><div class="cover" style="background: var(--default-bg-color)"></div><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">MiniShell</div></div></a></div><div class="next-post pull-right"><a href="/posts/1714087543/" title="SpringSecurity学习笔记"><div class="cover" style="background: var(--default-bg-color)"></div><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">SpringSecurity学习笔记</div></div></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="" data-original="https://q1.qlogo.cn/g?b=qq&amp;nk=2770063826&amp;s=640" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">Jixer</div><div class="author-info__description"></div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">52</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">19</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">7</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/2770063826"><i class="fab fa-github"></i><span>Follow Me</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content"></div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA"><span class="toc-text">环境搭建</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%8D%E4%B9%A0"><span class="toc-text">复习</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#DependencyManagement%E5%92%8CDependencies"><span class="toc-text">DependencyManagement和Dependencies</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Maven%E8%B7%B3%E8%BF%87%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95"><span class="toc-text">Maven跳过单元测试</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Dashboard%E7%AA%97%E5%8F%A3"><span class="toc-text">Dashboard窗口</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%94%AF%E4%BB%98%E6%A8%A1%E5%9D%97%E6%9E%84%E5%BB%BA"><span class="toc-text">支付模块构建</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B6%88%E8%B4%B9%E6%A8%A1%E5%9D%97%E6%9E%84%E5%BB%BA"><span class="toc-text">消费模块构建</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Restemplate"><span class="toc-text">Restemplate</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B7%A5%E7%A8%8B%E9%87%8D%E6%9E%84"><span class="toc-text">工程重构</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%9F%A5%E8%AF%86%E7%82%B9"><span class="toc-text">知识点</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83"><span class="toc-text">服务注册中心</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Eureka"><span class="toc-text">Eureka</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86"><span class="toc-text">基础知识</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#EurekaServer%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%AE%89%E8%A3%85"><span class="toc-text">EurekaServer服务端安装</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%94%AF%E4%BB%98%E5%BE%AE%E6%9C%8D%E5%8A%A18001%E5%85%A5%E9%A9%BB%E8%BF%9BEurekaServer"><span class="toc-text">支付微服务8001入驻进EurekaServer</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%AE%A2%E5%8D%95%E5%BE%AE%E6%9C%8D%E5%8A%A180%E5%85%A5%E9%A9%BB%E8%BF%9BEurekaServer"><span class="toc-text">订单微服务80入驻进EurekaServer</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Eureka%E9%9B%86%E7%BE%A4%E5%8E%9F%E7%90%86%E8%AF%B4%E6%98%8E"><span class="toc-text">Eureka集群原理说明</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Eureka%E9%9B%86%E7%BE%A4%E7%8E%AF%E5%A2%83%E6%9E%84%E5%BB%BA"><span class="toc-text">Eureka集群环境构建</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%AE%A2%E5%8D%95%E6%94%AF%E4%BB%98%E4%B8%A4%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E8%BF%9BEureka%E9%9B%86%E7%BE%A4"><span class="toc-text">订单支付两微服务注册进Eureka集群</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%94%AF%E4%BB%98%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%9B%86%E7%BE%A4%E9%85%8D%E7%BD%AE"><span class="toc-text">支付微服务集群配置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#actuator%E5%BE%AE%E6%9C%8D%E5%8A%A1%E4%BF%A1%E6%81%AF%E5%AE%8C%E5%96%84"><span class="toc-text">actuator微服务信息完善</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0Discovery"><span class="toc-text">服务发现Discovery</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Eureka%E8%87%AA%E6%88%91%E4%BF%9D%E6%8A%A4%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86"><span class="toc-text">Eureka自我保护理论知识</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Zookeeper"><span class="toc-text">Zookeeper</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%94%AF%E4%BB%98%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E8%BF%9Bzookeeper"><span class="toc-text">支付服务注册进zookeeper</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%AE%A2%E5%8D%95%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E8%BF%9Bzookeeper"><span class="toc-text">订单服务注册进zookeeper</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Consul"><span class="toc-text">Consul</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%B3%A8%E5%86%8C%E8%BF%9BConsul"><span class="toc-text">服务提供者注册进Consul</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E6%B3%A8%E5%86%8C%E8%BF%9BConsul"><span class="toc-text">服务消费者注册进Consul</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%89%E4%B8%AA%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%BC%82%E5%90%8C%E7%82%B9"><span class="toc-text">三个注册中心异同点</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#AP%E6%9E%B6%E6%9E%84%EF%BC%88Eureka%EF%BC%89"><span class="toc-text">AP架构（Eureka）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CP%E6%9E%B6%E6%9E%84%EF%BC%88ZooKeeper-Consul%EF%BC%89"><span class="toc-text">CP架构（ZooKeeper&#x2F;Consul）</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8"><span class="toc-text">服务调用</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Ribbon"><span class="toc-text">Ribbon</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Ribbon%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%92%8CRest%E8%B0%83%E7%94%A8"><span class="toc-text">Ribbon的负载均衡和Rest调用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Ribbon%E9%BB%98%E8%AE%A4%E8%87%AA%E5%B8%A6%E7%9A%84%E8%B4%9F%E8%BD%BD%E8%A7%84%E5%88%99"><span class="toc-text">Ribbon默认自带的负载规则</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#OpenFeign"><span class="toc-text">OpenFeign</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Feign%E5%92%8COpenFeign%E4%B8%A4%E8%80%85%E5%8C%BA%E5%88%AB"><span class="toc-text">Feign和OpenFeign两者区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#OpenFeign%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8"><span class="toc-text">OpenFeign服务调用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#OpenFeign%E8%B6%85%E6%97%B6%E6%8E%A7%E5%88%B6"><span class="toc-text">OpenFeign超时控制</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#OpenFeign%E6%97%A5%E5%BF%97%E5%A2%9E%E5%BC%BA"><span class="toc-text">OpenFeign日志增强</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7"><span class="toc-text">服务降级</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Hystrix"><span class="toc-text">Hystrix</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E6%94%AF%E4%BB%98%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%84%E5%BB%BA"><span class="toc-text">Hystrix支付微服务构建</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#JMeter%E9%AB%98%E5%B9%B6%E5%8F%91%E5%8E%8B%E6%B5%8B%E5%90%8E%E5%8D%A1%E9%A1%BF"><span class="toc-text">JMeter高并发压测后卡顿</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E8%AE%A2%E5%8D%95%E5%BE%AE%E6%9C%8D%E5%8A%A1"><span class="toc-text">Hystrix订单微服务</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%99%8D%E7%BA%A7%E5%AE%B9%E9%94%99%E8%A7%A3%E5%86%B3%E7%9A%84%E7%BB%B4%E5%BA%A6%E8%A6%81%E6%B1%82"><span class="toc-text">降级容错解决的维度要求</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E6%94%AF%E4%BB%98fallback"><span class="toc-text">Hystrix服务降级支付fallback</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E8%AE%A2%E5%8D%95fallback"><span class="toc-text">Hystrix服务降级订单fallback</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E5%85%A8%E5%B1%80%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7DefaultProperties"><span class="toc-text">Hystrix全局服务降级DefaultProperties</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E9%80%9A%E9%85%8D%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7FeignFallback"><span class="toc-text">Hystrix通配服务降级FeignFallback</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%E7%90%86%E8%AE%BA"><span class="toc-text">Hystrix服务熔断理论</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E4%B9%8B%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%E6%A1%88%E4%BE%8B"><span class="toc-text">Hystrix之服务熔断案例</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%E6%80%BB%E7%BB%93"><span class="toc-text">Hystrix服务熔断总结</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E5%9B%BE%E5%BD%A2%E5%8C%96Dashboard%E6%90%AD%E5%BB%BA"><span class="toc-text">Hystrix图形化Dashboard搭建</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Hystrix%E5%9B%BE%E5%BD%A2%E5%8C%96Dashboard%E7%9B%91%E6%8E%A7%E5%AE%9E%E6%88%98"><span class="toc-text">Hystrix图形化Dashboard监控实战</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E7%BD%91%E5%85%B3"><span class="toc-text">服务网关</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#GateWay"><span class="toc-text">GateWay</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Gateway%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B"><span class="toc-text">Gateway工作流程</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Gateway9527%E6%90%AD%E5%BB%BA"><span class="toc-text">Gateway9527搭建</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Gateway%E9%85%8D%E7%BD%AE%E8%B7%AF%E7%94%B1%E7%9A%84%E4%B8%A4%E7%A7%8D%E6%96%B9%E5%BC%8F"><span class="toc-text">Gateway配置路由的两种方式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#GateWay%E9%85%8D%E7%BD%AE%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1"><span class="toc-text">GateWay配置动态路由</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#GateWay%E5%B8%B8%E7%94%A8%E7%9A%84Predicate"><span class="toc-text">GateWay常用的Predicate</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#GateWay%E7%9A%84Filter"><span class="toc-text">GateWay的Filter</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E9%85%8D%E7%BD%AE"><span class="toc-text">服务配置</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#config"><span class="toc-text">config</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Config%E5%88%86%E5%B8%83%E5%BC%8F%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E4%BB%8B%E7%BB%8D"><span class="toc-text">Config分布式配置中心介绍</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Config%E9%85%8D%E7%BD%AE%E6%80%BB%E6%8E%A7%E4%B8%AD%E5%BF%83%E6%90%AD%E5%BB%BA"><span class="toc-text">Config配置总控中心搭建</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Config%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%85%8D%E7%BD%AE%E4%B8%8E%E6%B5%8B%E8%AF%95"><span class="toc-text">Config客户端配置与测试</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Config%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E6%89%8B%E5%8A%A8%E7%89%88"><span class="toc-text">Config动态刷新手动版</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B6%88%E6%81%AF%E6%80%BB%E7%BA%BF"><span class="toc-text">消息总线</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#RabbitMQ"><span class="toc-text">RabbitMQ</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE"><span class="toc-text">环境配置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Bus%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E5%85%A8%E5%B1%80%E5%B9%BF%E6%92%AD%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%80%9D%E6%83%B3%E5%92%8C%E9%80%89%E5%9E%8B"><span class="toc-text">Bus动态刷新全局广播的设计思想和选型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Bus%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E5%85%A8%E5%B1%80%E5%B9%BF%E6%92%AD%E9%85%8D%E7%BD%AE%E5%AE%9E%E7%8E%B0"><span class="toc-text">Bus动态刷新全局广播配置实现</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Bus%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E5%AE%9A%E7%82%B9%E9%80%9A%E7%9F%A5"><span class="toc-text">Bus动态刷新定点通知</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B6%88%E6%81%AF%E9%A9%B1%E5%8A%A8"><span class="toc-text">消息驱动</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Stream"><span class="toc-text">Stream</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%AE%BE%E8%AE%A1%E6%80%9D%E6%83%B3"><span class="toc-text">设计思想</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%B8%B8%E7%94%A8%E6%B3%A8%E8%A7%A3"><span class="toc-text">常用注解</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Stream%E6%B6%88%E6%81%AF%E9%A9%B1%E5%8A%A8%E4%B9%8B%E7%94%9F%E4%BA%A7%E8%80%85"><span class="toc-text">Stream消息驱动之生产者</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Stream%E6%B6%88%E6%81%AF%E9%A9%B1%E5%8A%A8%E4%B9%8B%E6%B6%88%E8%B4%B9%E8%80%85"><span class="toc-text">Stream消息驱动之消费者</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Stream%E4%B9%8B%E6%B6%88%E6%81%AF%E9%87%8D%E5%A4%8D%E6%B6%88%E8%B4%B9"><span class="toc-text">Stream之消息重复消费</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Stream%E4%B9%8B%E6%B6%88%E6%81%AF%E6%8C%81%E4%B9%85%E5%8C%96"><span class="toc-text">Stream之消息持久化</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%86%E5%B8%83%E5%BC%8F%E8%AF%B7%E6%B1%82%E9%93%BE%E8%B7%AF%E8%B7%9F%E8%B8%AA"><span class="toc-text">分布式请求链路跟踪</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Sleuth"><span class="toc-text">Sleuth</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Sleuth%E4%B9%8Bzipkin%E6%90%AD%E5%BB%BA%E5%AE%89%E8%A3%85"><span class="toc-text">Sleuth之zipkin搭建安装</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sleuth%E9%93%BE%E8%B7%AF%E7%9B%91%E6%8E%A7%E5%B1%95%E7%8E%B0"><span class="toc-text">Sleuth链路监控展现</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Spring-Cloud-Alibaba"><span class="toc-text">Spring Cloud Alibaba</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Nacos"><span class="toc-text">Nacos</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E4%BB%8B%E7%BB%8D"><span class="toc-text">Nacos介绍</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E5%AE%89%E8%A3%85"><span class="toc-text">Nacos安装</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E4%B9%8B%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%B3%A8%E5%86%8C"><span class="toc-text">Nacos之服务提供者注册</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E4%B9%8B%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E6%B3%A8%E5%86%8C%E5%92%8C%E8%B4%9F%E8%BD%BD"><span class="toc-text">Nacos之服务消费者注册和负载</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E4%B9%8B%E6%9C%8D%E5%8A%A1%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83"><span class="toc-text">Nacos之服务配置中心</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E4%B9%8B%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E5%88%86%E7%BB%84%E5%92%8CDataID%E4%B8%89%E8%80%85%E5%85%B3%E7%B3%BB"><span class="toc-text">Nacos之命名空间分组和DataID三者关系</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E4%B9%8BDataID%E9%85%8D%E7%BD%AE"><span class="toc-text">Nacos之DataID配置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E4%B9%8BGroup%E5%88%86%E7%BB%84%E6%96%B9%E6%A1%88"><span class="toc-text">Nacos之Group分组方案</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E4%B9%8BNamespace%E7%A9%BA%E9%97%B4%E6%96%B9%E6%A1%88"><span class="toc-text">Nacos之Namespace空间方案</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E6%8C%81%E4%B9%85%E5%8C%96%E5%88%87%E6%8D%A2%E9%85%8D%E7%BD%AE"><span class="toc-text">Nacos持久化切换配置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Nacos%E9%9B%86%E7%BE%A4%E9%85%8D%E7%BD%AE"><span class="toc-text">Nacos集群配置</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Sentinel"><span class="toc-text">Sentinel</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E4%BB%8B%E7%BB%8D"><span class="toc-text">Sentinel介绍</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E8%BF%90%E8%A1%8C"><span class="toc-text">Sentinel下载安装运行</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9B%91%E6%8E%A7"><span class="toc-text">Sentinel初始化监控</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%B5%81%E6%8E%A7%E8%A7%84%E5%88%99%E7%AE%80%E4%BB%8B"><span class="toc-text">Sentinel流控规则简介</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%B5%81%E6%8E%A7-QPS%E7%9B%B4%E6%8E%A5%E5%A4%B1%E8%B4%A5"><span class="toc-text">Sentinel流控-QPS直接失败</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%B5%81%E6%8E%A7-%E7%BA%BF%E7%A8%8B%E6%95%B0%E7%9B%B4%E6%8E%A5%E5%A4%B1%E8%B4%A5"><span class="toc-text">Sentinel流控-线程数直接失败</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%B5%81%E6%8E%A7-%E5%85%B3%E8%81%94"><span class="toc-text">Sentinel流控-关联</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%B5%81%E6%8E%A7-%E9%A2%84%E7%83%AD"><span class="toc-text">Sentinel流控-预热</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%B5%81%E6%8E%A7-%E6%8E%92%E9%98%9F%E7%AD%89%E5%BE%85"><span class="toc-text">Sentinel流控-排队等待</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E9%99%8D%E7%BA%A7%E7%AE%80%E4%BB%8B"><span class="toc-text">Sentinel降级简介</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E9%99%8D%E7%BA%A7-RT"><span class="toc-text">Sentinel降级-RT</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E9%99%8D%E7%BA%A7-%E5%BC%82%E5%B8%B8%E6%AF%94%E4%BE%8B"><span class="toc-text">Sentinel降级-异常比例</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E9%99%8D%E7%BA%A7-%E5%BC%82%E5%B8%B8%E6%95%B0"><span class="toc-text">Sentinel降级-异常数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E7%83%AD%E7%82%B9key-%E4%B8%8A"><span class="toc-text">Sentinel热点key(上)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E7%83%AD%E7%82%B9key-%E4%B8%8B"><span class="toc-text">Sentinel热点key(下)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E7%B3%BB%E7%BB%9F%E8%A7%84%E5%88%99"><span class="toc-text">Sentinel系统规则</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#SentinelResource%E9%85%8D%E7%BD%AE-%E4%B8%8A"><span class="toc-text">SentinelResource配置(上)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#SentinelResource%E9%85%8D%E7%BD%AE-%E4%B8%AD"><span class="toc-text">SentinelResource配置(中)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#SentinelResource%E9%85%8D%E7%BD%AE-%E4%B8%8B"><span class="toc-text">SentinelResource配置(下)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%ADRibbon%E7%8E%AF%E5%A2%83%E9%A2%84%E8%AF%B4"><span class="toc-text">Sentinel服务熔断Ribbon环境预说</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%E5%8F%AA%E9%85%8D%E7%BD%AEfallback"><span class="toc-text">Sentinel服务熔断只配置fallback</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%E5%8F%AA%E9%85%8D%E7%BD%AEblockHandler"><span class="toc-text">Sentinel服务熔断只配置blockHandler</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%ADfallback%E5%92%8CblockHandler%E9%83%BD%E9%85%8D%E7%BD%AE"><span class="toc-text">Sentinel服务熔断fallback和blockHandler都配置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%ADexceptionsToIgnore"><span class="toc-text">Sentinel服务熔断exceptionsToIgnore</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%ADOpenFeign"><span class="toc-text">Sentinel服务熔断OpenFeign</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Sentinel%E6%8C%81%E4%B9%85%E5%8C%96%E8%A7%84%E5%88%99"><span class="toc-text">Sentinel持久化规则</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Seata"><span class="toc-text">Seata</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E9%97%AE%E9%A2%98%E7%94%B1%E6%9D%A5"><span class="toc-text">分布式事务问题由来</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Seata%E6%9C%AF%E8%AF%AD"><span class="toc-text">Seata术语</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Seata-Server%E5%AE%89%E8%A3%85"><span class="toc-text">Seata-Server安装</span></a></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/posts/2029624507/" title="2022年算法队选拔赛">2022年算法队选拔赛</a><time datetime="2024-05-09T15:00:27.000Z" title="发表于 2024-05-09 23:00:27">2024-05-09</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/posts/1978524057/" title="牛客小白月赛84">牛客小白月赛84</a><time datetime="2024-05-08T14:40:35.000Z" title="发表于 2024-05-08 22:40:35">2024-05-08</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/posts/131339317/" title="软件测试资料">软件测试资料</a><time datetime="2024-05-07T03:12:52.000Z" title="发表于 2024-05-07 11:12:52">2024-05-07</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/posts/2394234105/" title="第十四届蓝桥杯B组国赛">第十四届蓝桥杯B组国赛</a><time datetime="2024-05-05T13:40:15.000Z" title="发表于 2024-05-05 21:40:15">2024-05-05</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/posts/1405472621/" title="Leetcode第396场周赛">Leetcode第396场周赛</a><time datetime="2024-05-05T03:58:25.000Z" title="发表于 2024-05-05 11:58:25">2024-05-05</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2024 By Jixer</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><a href="https://beian.miit.gov.cn/#/Integrated/index" style="color:white" target="_blank">蜀ICP备2022009955号-1</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js?v=4.13.0"></script><script src="/js/main.js?v=4.13.0"></script><script src="/pluginsSrc/@fancyapps/ui/dist/fancybox/fancybox.umd.js?v=5.0.33"></script><div class="js-pjax"></div><script src="/js/custom-fancybox-umd-min.js"></script><script src="/js/custom-busuanzi-pure-mini.js"></script><script src="/js/Valine.min.js"></script><script src="/js/custom-social-share.min.js"></script><script src="/js/custom-typed-umd-min.js"></script><script src="/js/av-min.js"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js?v=4.13.0"></script></div></div>
        <style>
            [bg-lazy] {
                background-image: none !important;
                background-color: #eee !important;
            }
        </style>
        <script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(r){r.imageLazyLoadSetting.processImages=t;var e=r.imageLazyLoadSetting.isSPA,n=r.imageLazyLoadSetting.preloadRatio||1,c=a();function a(){var t=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")),e=Array.prototype.slice.call(document.querySelectorAll("[bg-lazy]"));return t.concat(e)}function t(){e&&(c=a());for(var t,o=0;o<c.length;o++)0<=(t=(t=c[o]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(r.innerHeight*n||document.documentElement.clientHeight*n)&&function(){var t,e,n,a,i=c[o];e=function(){c=c.filter(function(t){return i!==t}),r.imageLazyLoadSetting.onImageLoaded&&r.imageLazyLoadSetting.onImageLoaded(i)},(t=i).hasAttribute("bg-lazy")?(t.removeAttribute("bg-lazy"),e&&e()):(n=new Image,a=t.getAttribute("data-original"),n.onload=function(){t.src=a,t.removeAttribute("data-original"),e&&e()},t.src!==a&&(n.src=a))}()}function i(){clearTimeout(t.tId),t.tId=setTimeout(t,500)}t(),document.addEventListener("scroll",i),r.addEventListener("resize",i),r.addEventListener("orientationchange",i)}(this);</script></body></html>